Quantcast
Channel: Active questions tagged react-native+typescript - Stack Overflow
Viewing all articles
Browse latest Browse all 6581

React Native AsyncStorage save Issue

$
0
0

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: +39749317801User found for phone number +39749317801: nullStaff found for phone number +39749317801: {  _id: new ObjectId('66701c0679dd0b697f6fab8e'),  name: 'Test',  email: 'test@test.co',  phoneNumber: '+39749317801',  password: '-',  restaurant: new ObjectId('66462c14dccbc277a0dce424'),  role: 'delivery',  isVerified: true,  refreshToken: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjp7ImlkIjoiNjY3MDFjMDY3OWRkMGI2OTdmNmZhYjhlIiwicm9sZSI6ImRlbGl2ZXJ5In0sImlhdCI6MTcxODcyNzQ2NywiZXhwIjoxNzE5MzMyMjY3fQ.YWpZGK6QPzvRmECeUSdRUy0VxXGG-DQEBMsJ2DAtV-M',  __v: 0}Received token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjp7ImlkIjoiNjY3MDFjMDY3OWRkMGI2OTdmNmZhYjhlIiwicm9sZSI6ImRlbGl2ZXJ5In0sImlhdCI6MTcxODcyNzg5MiwiZXhwIjoxNzE4NzI4MDcyfQ.qv1IkRAnSYG26RZv-_hwijfkNX0DAhHMamjBlfaKLY8Received refresh token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjp7ImlkIjoiNjY3MDFjMDY3OWRkMGI2OTdmNmZhYjhlIiwicm9sZSI6ImRlbGl2ZXJ5In0sImlhdCI6MTcxODcyNzg5MiwiZXhwIjoxNzE5MzMyNjkyfQ.denkXXZhCDww3FUSlBFeFk93YlYdMnFHrfBmrrXQO_MToken verified successfully, user: { id: '66701c0679dd0b697f6fab8e', role: 'delivery' }Received token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjp7ImlkIjoiNjY3MDFjMDY3OWRkMGI2OTdmNmZhYjhlIiwicm9sZSI6ImRlbGl2ZXJ5In0sImlhdCI6MTcxODcyNzg5MiwiZXhwIjoxNzE4NzI4MDcyfQ.qv1IkRAnSYG26RZv-_hwijfkNX0DAhHMamjBlfaKLY8Received refresh token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjp7ImlkIjoiNjY3MDFjMDY3OWRkMGI2OTdmNmZhYjhlIiwicm9sZSI6ImRlbGl2ZXJ5In0sImlhdCI6MTcxODcyNzg5MiwiZXhwIjoxNzE5MzMyNjkyfQ.denkXXZhCDww3FUSlBFeFk93YlYdMnFHrfBmrrXQO_MToken expired, attempting to refreshDecoded refresh token, userId: 66701c0679dd0b697f6fab8eFound user with refresh token: {  _id: new ObjectId('66701c0679dd0b697f6fab8e'),  name: 'test',  email: 'test@test.co',  phoneNumber: '+39749317801',  password: '-',  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_FKcViZ0CJdEjmdSDsGenerated new tokens: {  newToken: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjp7ImlkIjoiNjY3MDFjMDY3OWRkMGI2OTdmNmZhYjhlIiwicm9sZSI6ImRlbGl2ZXJ5In0sImlhdCI6MTcxODcyODQyOSwiZXhwIjoxNzE4NzI4NzI5fQ.qLQRGN_3JLJmClWe28r2FnGWmcLi6NyNJYYST0slmMo',  newRefreshToken: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjp7ImlkIjoiNjY3MDFjMDY3OWRkMGI2OTdmNmZhYjhlIiwicm9sZSI6ImRlbGl2ZXJ5In0sImlhdCI6MTcxODcyODQyOSwiZXhwIjoxNzE5MzMzMjI5fQ.xLdJCCwvuqAnSDBFr1RZX9vNk_FKcViZ0CJdEjmdSDs'}Received token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjp7ImlkIjoiNjY3MDFjMDY3OWRkMGI2OTdmNmZhYjhlIiwicm9sZSI6ImRlbGl2ZXJ5In0sImlhdCI6MTcxODcyNzg5MiwiZXhwIjoxNzE4NzI4MDcyfQ.qv1IkRAnSYG26RZv-_hwijfkNX0DAhHMamjBlfaKLY8Received refresh token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjp7ImlkIjoiNjY3MDFjMDY3OWRkMGI2OTdmNmZhYjhlIiwicm9sZSI6ImRlbGl2ZXJ5In0sImlhdCI6MTcxODcyNzg5MiwiZXhwIjoxNzE5MzMyNjkyfQ.denkXXZhCDww3FUSlBFeFk93YlYdMnFHrfBmrrXQO_MToken expired, attempting to refreshDecoded refresh token, userId: 66701c0679dd0b697f6fab8eFound user with refresh token: {  _id: new ObjectId('66701c0679dd0b697f6fab8e'),  name: 'Test',  email: 'test@test.co',  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


Viewing all articles
Browse latest Browse all 6581

Latest Images

Trending Articles



Latest Images