Lesson 129 of 158 – React Native AsyncStorage Token
82%

React Native AsyncStorage Token

After a successful login, a React Native application needs a way to remember authentication information when appropriate. AsyncStorage can store persistent application data on the device. In this lesson, we will learn how to use AsyncStorage with JWT authentication.

Note: AsyncStorage is useful for persistent application data, but it is not designed as secure storage for highly sensitive secrets. For sensitive authentication tokens, consider a platform secure-storage solution.

1. What is AsyncStorage?

AsyncStorage is a persistent key-value storage system commonly used in React Native applications.

Data stored in AsyncStorage can remain available after the application is closed and opened again.

Key → Value

2. Installing AsyncStorage

Install the AsyncStorage package in a React Native project.

npm install @react-native-async-storage/async-storage

With Expo, the package can also be installed using:

npx expo install @react-native-async-storage/async-storage

3. Importing AsyncStorage

import AsyncStorage
    from "@react-native-async-storage/async-storage";

The imported object provides asynchronous methods for storing and retrieving values.

4. Storing a Token

Use setItem() to store a value.

await AsyncStorage.setItem(
    "authToken",
    token
);

The token is stored using the key authToken.

5. Reading a Token

Use getItem() to retrieve a stored value.

const token =
    await AsyncStorage.getItem(
        "authToken"
    );

console.log(token);

6. Removing a Token

Use removeItem() when the application needs to remove the locally stored token.

await AsyncStorage.removeItem(
    "authToken"
);

This is commonly used during logout.

7. AsyncStorage is Asynchronous

AsyncStorage methods return promises, so await can be used inside an asynchronous function.

const loadToken = async () => {

    const token =
        await AsyncStorage.getItem(
            "authToken"
        );

    console.log(token);
};

8. Token After Login

After a successful login, the API can return a JWT token.

const result =
    await login({
        email,
        password
    });

if (result.success) {

    await AsyncStorage.setItem(
        "authToken",
        result.token
    );
}

9. Saving the User ID

If needed, non-sensitive user information can also be stored.

await AsyncStorage.setItem(
    "userId",
    String(result.user.id)
);

When storing objects or structured data, use JSON serialization.

10. Storing an Object

AsyncStorage stores strings. Therefore, an object must be converted to JSON before storing it.

const user = {
    id: 101,
    name: "Rahul",
    email: "rahul@example.com"
};

await AsyncStorage.setItem(
    "user",
    JSON.stringify(user)
);

11. Reading an Object

const storedUser =
    await AsyncStorage.getItem(
        "user"
    );

if (storedUser) {

    const user =
        JSON.parse(storedUser);

    console.log(user.name);
}

12. Token Type in TypeScript

A token retrieved from AsyncStorage can be either a string or null.

const token: string | null =
    await AsyncStorage.getItem(
        "authToken"
    );

The value is null when the key does not exist.

13. Authentication State

interface AuthState {
    token: string | null;
    user: User | null;
    isAuthenticated: boolean;
}

The application can use this state to represent the current authentication status.

14. Loading Token on App Start

const loadToken = async () => {

    const token =
        await AsyncStorage.getItem(
            "authToken"
        );

    if (token) {
        console.log(
            "Token found"
        );
    } else {
        console.log(
            "No token found"
        );
    }
};

15. Using useEffect

useEffect(() => {

    const initializeAuth =
        async () => {

        const token =
            await AsyncStorage.getItem(
                "authToken"
            );

        console.log(token);
    };

    initializeAuth();

}, []);

16. Restoring Authentication State

const initializeAuth = async () => {

    const token =
        await AsyncStorage.getItem(
            "authToken"
        );

    if (token) {

        setAuth({
            token,
            user: null,
            isAuthenticated: true
        });

    } else {

        setAuth({
            token: null,
            user: null,
            isAuthenticated: false
        });
    }
};

17. Saving Login Data

if (result.success) {

    await AsyncStorage.setItem(
        "authToken",
        result.token
    );

    await AsyncStorage.setItem(
        "user",
        JSON.stringify(result.user)
    );
}

18. Restoring Login Data

const token =
    await AsyncStorage.getItem(
        "authToken"
    );

const storedUser =
    await AsyncStorage.getItem(
        "user"
    );

if (token && storedUser) {

    const user =
        JSON.parse(storedUser);

    console.log(user.name);
}

19. Logout with AsyncStorage

const logout = async () => {

    await AsyncStorage.removeItem(
        "authToken"
    );

    await AsyncStorage.removeItem(
        "user"
    );

    setAuth({
        token: null,
        user: null,
        isAuthenticated: false
    });
};

Removing the local token prevents the application from continuing to use that locally stored authentication state.

20. AsyncStorage with Axios

const getToken = async () => {

    return await AsyncStorage.getItem(
        "authToken"
    );
};

const loadProfile = async () => {

    const token =
        await getToken();

    const response =
        await api.get(
            "/profile.php",
            {
                headers: {
                    Authorization:
                        `Bearer ${token}`
                }
            }
        );

    return response.data;
};

21. Axios Request Interceptor

An Axios request interceptor can read the token before a request is sent.

api.interceptors.request.use(
    async config => {

        const token =
            await AsyncStorage.getItem(
                "authToken"
            );

        if (token) {

            config.headers.Authorization =
                `Bearer ${token}`;
        }

        return config;
    }
);

22. Handling Missing Token

const token =
    await AsyncStorage.getItem(
        "authToken"
    );

if (!token) {

    console.log(
        "User is not logged in"
    );

    return;
}

A missing token can be used to determine that there is no locally available authenticated session.

23. Handling Expired Token

AsyncStorage does not verify whether a JWT is valid or expired. The server must validate the token.

try {

    const response =
        await api.get(
            "/profile.php"
        );

} catch (error) {

    if (
        axios.isAxiosError(error) &&
        error.response?.status === 401
    ) {

        await AsyncStorage.removeItem(
            "authToken"
        );
    }
}

24. Secure Storage Consideration

AsyncStorage is persistent storage, but it should not be considered a secure vault for highly sensitive secrets.

For sensitive authentication tokens, a platform secure-storage solution can provide stronger protection depending on the application and threat model.

  • Keep server secrets on the server.
  • Never store the JWT signing secret in the mobile app.
  • Use HTTPS.
  • Choose appropriate secure storage for sensitive tokens.

25. AsyncStorage Helper Functions

const saveToken = async (
    token: string
) => {

    await AsyncStorage.setItem(
        "authToken",
        token
    );
};

const getToken = async (): Promise<
    string | null
> => {

    return await AsyncStorage.getItem(
        "authToken"
    );
};

const removeToken = async () => {

    await AsyncStorage.removeItem(
        "authToken"
    );
};

26. Complete Authentication Storage Service

import AsyncStorage
    from "@react-native-async-storage/async-storage";

const TOKEN_KEY = "authToken";
const USER_KEY = "authUser";

export const saveAuth =
    async (
        token: string,
        user: User
    ) => {

    await AsyncStorage.setItem(
        TOKEN_KEY,
        token
    );

    await AsyncStorage.setItem(
        USER_KEY,
        JSON.stringify(user)
    );
};

export const getAuth =
    async () => {

    const token =
        await AsyncStorage.getItem(
            TOKEN_KEY
        );

    const userData =
        await AsyncStorage.getItem(
            USER_KEY
        );

    const user =
        userData
            ? JSON.parse(userData)
            : null;

    return {
        token,
        user
    };
};

export const clearAuth =
    async () => {

    await AsyncStorage.multiRemove([
        TOKEN_KEY,
        USER_KEY
    ]);
};

27. Using multiSet and multiRemove

Multiple key-value pairs can be handled together.

await AsyncStorage.multiSet([
    ["authToken", token],
    ["userId", String(user.id)]
]);

Multiple values can also be removed together.

await AsyncStorage.multiRemove([
    "authToken",
    "userId"
]);

28. Complete Login + AsyncStorage Flow

const handleLogin = async () => {

    try {

        const result =
            await login({
                email,
                password
            });

        if (result.success) {

            await AsyncStorage.setItem(
                "authToken",
                result.token
            );

            await AsyncStorage.setItem(
                "authUser",
                JSON.stringify(
                    result.user
                )
            );

            setAuth({
                token: result.token,
                user: result.user,
                isAuthenticated: true
            });
        }

    } catch (error) {

        console.log(
            "Login failed"
        );
    }
};

29. App Startup Authentication Check

const checkAuthentication =
    async () => {

    const token =
        await AsyncStorage.getItem(
            "authToken"
        );

    const userData =
        await AsyncStorage.getItem(
            "authUser"
        );

    if (token && userData) {

        const user =
            JSON.parse(userData);

        setAuth({
            token,
            user,
            isAuthenticated: true
        });

    } else {

        setAuth({
            token: null,
            user: null,
            isAuthenticated: false
        });
    }
};

This allows the application to restore its local authentication state when it starts. The server should still validate the token before granting access to protected resources.

30. Complete JWT + AsyncStorage Flow

1. User logs in
2. React Native sends credentials
3. PHP verifies credentials
4. PHP returns JWT
5. React Native receives JWT
6. Token is stored locally
7. User closes the application
8. Application starts again
9. Token is loaded from storage
10. Authentication state is restored
11. Axios sends Bearer JWT
12. PHP verifies JWT
13. Protected API returns data
14. Logout removes local authentication data

AsyncStorage can help maintain persistent application state, while the backend remains responsible for validating the JWT. For sensitive authentication credentials, use an appropriate secure storage mechanism rather than treating AsyncStorage as a secure vault.

📌 Key Points

  • AsyncStorage provides persistent key-value storage in React Native.
  • setItem() stores a value.
  • getItem() retrieves a value.
  • removeItem() removes a value.
  • AsyncStorage stores strings, so objects should be serialized with JSON.
  • A missing token is represented by null.
  • AsyncStorage can help restore authentication state after app restart.
  • JWT validity must be checked by the server.
  • Logout can remove locally stored authentication state.
  • Highly sensitive tokens should use an appropriate secure-storage solution when required.

🧠 Quick Quiz

Question: Which AsyncStorage method is used to retrieve a stored token?