React Native AsyncStorage save Issue

I’m encountering an issue in my React Native app where the refresh token generated during authentication isn’t persisting in AsyncStorage. Despite successfully fetching new tokens from the server, AsyncStorage fails to store them, causing subsequent requests to revert to the old tokens. As a beginner, I’m unsure why AsyncStorage isn’t saving the updated tokens correctly. Any advice or solutions on how to ensure AsyncStorage properly stores and retrieves refreshed tokens would be greatly appreciated. Thank you!

This is my auth middleware

import { Request, Response, NextFunction } from 'express';
import jwt, { JwtPayload } from 'jsonwebtoken';
import AppUser from '../models/AppUser';
import Staff from '../models/Staff';

export interface AuthRequest extends Request {
  user?: {
    id: string;
    role: string;
  };
}

const generateTokens = (user: any) => {
  const payload = { user: { id: user._id, role: user.role } };
  const token = jwt.sign(payload, process.env.JWT_SECRET as string, { expiresIn: '5m' });
  const refreshToken = jwt.sign(payload, process.env.REFRESH_TOKEN_SECRET as string, { expiresIn: '7d' });
  console.log('Generated tokens:', { token, refreshToken });
  return { token, refreshToken };
};

const auth = async (req: AuthRequest, res: Response, next: NextFunction) => {
  const jwtSecret = process.env.JWT_SECRET;
  const refreshTokenSecret = process.env.REFRESH_TOKEN_SECRET;

  if (!jwtSecret || !refreshTokenSecret) {
    console.error('JWT_SECRET or REFRESH_TOKEN_SECRET not defined');
    throw new Error('JWT_SECRET or REFRESH_TOKEN_SECRET not defined');
  }

  let token = req.header('x-auth-token');
  let refreshToken = req.header('x-refresh-token');

  console.log('Received token:', token);
  console.log('Received refresh token:', refreshToken);

  if (!token && !refreshToken) {
    console.error('No token, authorization denied');
    return res.status(401).json({ error: 'No token, authorization denied' });
  }

  if (token) {
    try {
      const decoded = jwt.verify(token, jwtSecret) as JwtPayload;
      req.user = decoded.user;
      console.log('Token verified successfully, user:', req.user);
      next();
    } catch (err) {
      if (err instanceof jwt.TokenExpiredError && refreshToken) {
        console.log('Token expired, attempting to refresh');
        try {
          const decodedRefresh = jwt.verify(refreshToken, refreshTokenSecret) as JwtPayload;
          const userId = decodedRefresh.user?.id;
          console.log('Decoded refresh token, userId:', userId);
          const user = await AppUser.findById(userId) || await Staff.findById(userId);

          if (!user) {
            console.error('Invalid refresh token: user not found');
            return res.status(403).json({ error: 'Invalid refresh token: user not found' });
          }

          console.log('Found user with refresh token:', user);

          if (user.refreshToken !== refreshToken) {
            console.error('Refresh token does not match. Expected:', user.refreshToken, 'Received:', refreshToken);
            return res.status(403).json({ error: 'Refresh token does not match' });
          }

          const { token: newToken, refreshToken: newRefreshToken } = generateTokens(user);
          user.refreshToken = newRefreshToken;
          await user.save();

          const updatedUser = await Staff.findById(userId);
          console.log('Updated User Refresh Token:', updatedUser?.refreshToken);

          console.log('Generated new tokens:', { newToken, newRefreshToken });

          res.setHeader('x-auth-token', newToken);
          res.setHeader('x-refresh-token', newRefreshToken);
          req.user = decodedRefresh.user;
          next();
        } catch (refreshErr) {
          console.error('Invalid refresh token:', refreshErr);
          return res.status(401).json({ error: 'Invalid refresh token' });
        }
      } else {
        console.error('Token is not valid:', err);
        return res.status(401).json({ error: 'Token is not valid' });
      }
    }
  } else if (refreshToken) {
    try {
      const decodedRefresh = jwt.verify(refreshToken, refreshTokenSecret) as JwtPayload;
      const userId = decodedRefresh.user?.id;
      console.log('Decoded refresh token, userId:', userId);
      const user = await AppUser.findById(userId) || await Staff.findById(userId);

      if (!user) {
        console.error('Invalid refresh token: user not found');
        return res.status(403).json({ error: 'Invalid refresh token: user not found' });
      }

      console.log('Found user with refresh token:', user);

      if (user.refreshToken !== refreshToken) {
        console.error('Refresh token does not match. Expected:', user.refreshToken, 'Received:', refreshToken);
        return res.status(403).json({ error: 'Refresh token does not match' });
      }

      const { token: newToken, refreshToken: newRefreshToken } = generateTokens(user);
      user.refreshToken = newRefreshToken;
      await user.save();

      const updatedUser = await Staff.findById(userId);
      console.log('Updated User Refresh Token:', updatedUser?.refreshToken);

      console.log('Generated new tokens:', { newToken, newRefreshToken });

      res.setHeader('x-auth-token', newToken);
      res.setHeader('x-refresh-token', newRefreshToken);
      req.user = decodedRefresh.user;
      next();
    } catch (refreshErr) {
      console.error('Invalid refresh token:', refreshErr);
      return res.status(401).json({ error: 'Invalid refresh token' });
    }
  }
};

export default auth;

AsyncStorageManager

import axios from 'axios';
import AsyncStorage from '@react-native-async-storage/async-storage';

export const BASE_URL = 'http://localhost:5001/api';

const api = axios.create({
  baseURL: BASE_URL,
});

let isRefreshing = false;
let failedQueue: any[] = [];

const processQueue = (error: any, token: string | null = null) => {
  failedQueue.forEach(prom => {
    if (error) {
      prom.reject(error);
    } else {
      prom.resolve(token);
    }
  });

  failedQueue = [];
};

api.interceptors.request.use(
  async config => {
    const token = await AsyncStorage.getItem('token');
    const refreshToken = await AsyncStorage.getItem('refreshToken');
    console.log('Request Token:', token);
    console.log('Request Refresh Token:', refreshToken);
    if (token) {
      config.headers['x-auth-token'] = token;
    }
    if (refreshToken) {
      config.headers['x-refresh-token'] = refreshToken;
    }
    return config;
  },
  error => {
    console.log('Request Interceptor Error:', error);
    return Promise.reject(error);
  }
);

api.interceptors.response.use(
  response => {
    console.log('Response:', response);
    return response;
  },
  async error => {
    const originalRequest = error.config;
    console.log('Response Error:', error);

    if (error.response.status === 401 && !originalRequest._retry) {
      if (isRefreshing) {
        return new Promise(function (resolve, reject) {
          failedQueue.push({ resolve, reject });
        }).then(token => {
          if (token) {
            originalRequest.headers['x-auth-token'] = token;
          }
          return axios(originalRequest);
        }).catch(err => {
          return Promise.reject(err);
        });
      }

      originalRequest._retry = true;
      isRefreshing = true;

      const refreshToken = await AsyncStorage.getItem('refreshToken');
      console.log('Attempting to refresh token with:', refreshToken);
      return new Promise(function (resolve, reject) {
        axios.post(`${BASE_URL}/auth/refresh-token`, { refreshToken })
          .then(async ({ data }) => {
            console.log('New Tokens:', data);
            await AsyncStorage.setItem('token', data.token);
            await AsyncStorage.setItem('refreshToken', data.refreshToken);
            
            // Verificare imediat după setare
            const savedToken = await AsyncStorage.getItem('token');
            const savedRefreshToken = await AsyncStorage.getItem('refreshToken');
            console.log('Saved Token:', savedToken);
            console.log('Saved Refresh Token:', savedRefreshToken);
            
            api.defaults.headers.common['x-auth-token'] = data.token;
            api.defaults.headers.common['x-refresh-token'] = data.refreshToken;
            originalRequest.headers['x-auth-token'] = data.token;
            processQueue(null, data.token);
            resolve(axios(originalRequest));
          })
          .catch((err) => {
            console.log('Refresh Token Error:', err);
            processQueue(err, null);
            AsyncStorage.removeItem('token');
            AsyncStorage.removeItem('refreshToken');
            reject(err);
          })
          .finally(() => {
            isRefreshing = false;
          });
      });
    }
    return Promise.reject(error);
  }
);

export default api;

and this is the log:

Formatted phone number for login: +39749317801
User found for phone number +39749317801: null
Staff found for phone number +39749317801: {
  _id: new ObjectId('66701c0679dd0b697f6fab8e'),
  name: 'Test',
  email: '[email protected]',
  phoneNumber: '+39749317801',
  password: '-',
  restaurant: new ObjectId('66462c14dccbc277a0dce424'),
  role: 'delivery',
  isVerified: true,
  refreshToken: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjp7ImlkIjoiNjY3MDFjMDY3OWRkMGI2OTdmNmZhYjhlIiwicm9sZSI6ImRlbGl2ZXJ5In0sImlhdCI6MTcxODcyNzQ2NywiZXhwIjoxNzE5MzMyMjY3fQ.YWpZGK6QPzvRmECeUSdRUy0VxXGG-DQEBMsJ2DAtV-M',
  __v: 0
}
Received token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjp7ImlkIjoiNjY3MDFjMDY3OWRkMGI2OTdmNmZhYjhlIiwicm9sZSI6ImRlbGl2ZXJ5In0sImlhdCI6MTcxODcyNzg5MiwiZXhwIjoxNzE4NzI4MDcyfQ.qv1IkRAnSYG26RZv-_hwijfkNX0DAhHMamjBlfaKLY8
Received refresh token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjp7ImlkIjoiNjY3MDFjMDY3OWRkMGI2OTdmNmZhYjhlIiwicm9sZSI6ImRlbGl2ZXJ5In0sImlhdCI6MTcxODcyNzg5MiwiZXhwIjoxNzE5MzMyNjkyfQ.denkXXZhCDww3FUSlBFeFk93YlYdMnFHrfBmrrXQO_M
Token verified successfully, user: { id: '66701c0679dd0b697f6fab8e', role: 'delivery' }
Received token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjp7ImlkIjoiNjY3MDFjMDY3OWRkMGI2OTdmNmZhYjhlIiwicm9sZSI6ImRlbGl2ZXJ5In0sImlhdCI6MTcxODcyNzg5MiwiZXhwIjoxNzE4NzI4MDcyfQ.qv1IkRAnSYG26RZv-_hwijfkNX0DAhHMamjBlfaKLY8
Received refresh token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjp7ImlkIjoiNjY3MDFjMDY3OWRkMGI2OTdmNmZhYjhlIiwicm9sZSI6ImRlbGl2ZXJ5In0sImlhdCI6MTcxODcyNzg5MiwiZXhwIjoxNzE5MzMyNjkyfQ.denkXXZhCDww3FUSlBFeFk93YlYdMnFHrfBmrrXQO_M
Token expired, attempting to refresh
Decoded refresh token, userId: 66701c0679dd0b697f6fab8e
Found user with refresh token: {
  _id: new ObjectId('66701c0679dd0b697f6fab8e'),
  name: 'Ionut',
  email: '[email protected]',
  phoneNumber: '+40749317801',
  password: '$2b$10$/blV6uwfnMBmGrIERnw0NuDj21y9sRxIaWvUVP1ZnCFsmHowHh2Ii',
  restaurant: new ObjectId('66462c14dccbc277a0dce424'),
  role: 'delivery',
  isVerified: true,
  refreshToken: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjp7ImlkIjoiNjY3MDFjMDY3OWRkMGI2OTdmNmZhYjhlIiwicm9sZSI6ImRlbGl2ZXJ5In0sImlhdCI6MTcxODcyNzg5MiwiZXhwIjoxNzE5MzMyNjkyfQ.denkXXZhCDww3FUSlBFeFk93YlYdMnFHrfBmrrXQO_M',
  __v: 0
}
Generated tokens: {
  token: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjp7ImlkIjoiNjY3MDFjMDY3OWRkMGI2OTdmNmZhYjhlIiwicm9sZSI6ImRlbGl2ZXJ5In0sImlhdCI6MTcxODcyODQyOSwiZXhwIjoxNzE4NzI4NzI5fQ.qLQRGN_3JLJmClWe28r2FnGWmcLi6NyNJYYST0slmMo',
  refreshToken: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjp7ImlkIjoiNjY3MDFjMDY3OWRkMGI2OTdmNmZhYjhlIiwicm9sZSI6ImRlbGl2ZXJ5In0sImlhdCI6MTcxODcyODQyOSwiZXhwIjoxNzE5MzMzMjI5fQ.xLdJCCwvuqAnSDBFr1RZX9vNk_FKcViZ0CJdEjmdSDs'
}
Updated User Refresh Token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjp7ImlkIjoiNjY3MDFjMDY3OWRkMGI2OTdmNmZhYjhlIiwicm9sZSI6ImRlbGl2ZXJ5In0sImlhdCI6MTcxODcyODQyOSwiZXhwIjoxNzE5MzMzMjI5fQ.xLdJCCwvuqAnSDBFr1RZX9vNk_FKcViZ0CJdEjmdSDs
Generated new tokens: {
  newToken: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjp7ImlkIjoiNjY3MDFjMDY3OWRkMGI2OTdmNmZhYjhlIiwicm9sZSI6ImRlbGl2ZXJ5In0sImlhdCI6MTcxODcyODQyOSwiZXhwIjoxNzE4NzI4NzI5fQ.qLQRGN_3JLJmClWe28r2FnGWmcLi6NyNJYYST0slmMo',
  newRefreshToken: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjp7ImlkIjoiNjY3MDFjMDY3OWRkMGI2OTdmNmZhYjhlIiwicm9sZSI6ImRlbGl2ZXJ5In0sImlhdCI6MTcxODcyODQyOSwiZXhwIjoxNzE5MzMzMjI5fQ.xLdJCCwvuqAnSDBFr1RZX9vNk_FKcViZ0CJdEjmdSDs'
}
Received token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjp7ImlkIjoiNjY3MDFjMDY3OWRkMGI2OTdmNmZhYjhlIiwicm9sZSI6ImRlbGl2ZXJ5In0sImlhdCI6MTcxODcyNzg5MiwiZXhwIjoxNzE4NzI4MDcyfQ.qv1IkRAnSYG26RZv-_hwijfkNX0DAhHMamjBlfaKLY8
Received refresh token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjp7ImlkIjoiNjY3MDFjMDY3OWRkMGI2OTdmNmZhYjhlIiwicm9sZSI6ImRlbGl2ZXJ5In0sImlhdCI6MTcxODcyNzg5MiwiZXhwIjoxNzE5MzMyNjkyfQ.denkXXZhCDww3FUSlBFeFk93YlYdMnFHrfBmrrXQO_M
Token expired, attempting to refresh
Decoded refresh token, userId: 66701c0679dd0b697f6fab8e
Found user with refresh token: {
  _id: new ObjectId('66701c0679dd0b697f6fab8e'),
  name: 'Test',
  email: '[email protected]',
  phoneNumber: '+39749317801',
  password: '-',
  restaurant: new ObjectId('66462c14dccbc277a0dce424'),
  role: 'delivery',
  isVerified: true,
  refreshToken: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjp7ImlkIjoiNjY3MDFjMDY3OWRkMGI2OTdmNmZhYjhlIiwicm9sZSI6ImRlbGl2ZXJ5In0sImlhdCI6MTcxODcyODQyOSwiZXhwIjoxNzE5MzMzMjI5fQ.xLdJCCwvuqAnSDBFr1RZX9vNk_FKcViZ0CJdEjmdSDs',
  __v: 0
}
Refresh token does not match. Expected: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjp7ImlkIjoiNjY3MDFjMDY3OWRkMGI2OTdmNmZhYjhlIiwicm9sZSI6ImRlbGl2ZXJ5In0sImlhdCI6MTcxODcyODQyOSwiZXhwIjoxNzE5MzMzMjI5fQ.xLdJCCwvuqAnSDBFr1RZX9vNk_FKcViZ0CJdEjmdSDs Received: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjp7ImlkIjoiNjY3MDFjMDY3OWRkMGI2OTdmNmZhYjhlIiwicm9sZSI6ImRlbGl2ZXJ5In0sImlhdCI6MTcxODcyNzg5MiwiZXhwIjoxNzE5MzMyNjkyfQ.denkXXZhCDww3FUSlBFeFk93YlYdMnFHrfBmrrXQO_M

Some advices about fix the issue

New contributor

Cost Iont is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật