Lesson 136 of 158 – React Native Redux Authentication
86%

React Native Redux Authentication

Redux can be used to manage authentication state centrally in a React Native application. Instead of keeping authentication information only inside individual screens, Redux can store the current user, token, loading state, and authentication status in one predictable state store.

Note: Redux manages authentication state on the client. It does not replace JWT verification or authorization on the PHP REST API. The server must continue to verify every protected request.

1. What is Redux Authentication?

Redux authentication means keeping login-related application state inside a Redux store.

Login
  ↓
Redux Store
  ↓
User + Token + Auth Status
  ↓
Protected Screens
  ↓
Axios
  ↓
PHP REST API

2. Why Use Redux for Authentication?

  • Centralizes authentication state.
  • Makes user information available across screens.
  • Provides predictable state updates.
  • Works well with Redux Toolkit.
  • Can coordinate login and logout actions.
  • Can work together with Axios and JWT authentication.

3. Authentication State

interface User {
    id: number;
    name: string;
    email: string;
    role: "admin" | "teacher" | "student";
}

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

4. Redux Toolkit

Redux Toolkit is the recommended approach for writing Redux logic. It reduces the amount of boilerplate code required for actions, reducers, and store configuration.

import {
    createSlice
} from "@reduxjs/toolkit";

5. Creating an Auth Slice

const initialState: AuthState = {
    user: null,
    token: null,
    isAuthenticated: false,
    loading: true
};

The initial state represents an application that is still checking whether an existing authentication session can be restored.

6. createSlice()

const authSlice =
    createSlice({
        name: "auth",
        initialState,
        reducers: {
        }
    });

The auth slice will contain authentication-related state and reducers.

7. Login Reducer

login: (
    state,
    action
) => {

    state.user =
        action.payload.user;

    state.token =
        action.payload.token;

    state.isAuthenticated =
        true;

    state.loading =
        false;
}

8. Logout Reducer

logout: state => {

    state.user = null;
    state.token = null;
    state.isAuthenticated = false;
    state.loading = false;
}

The logout reducer resets the authentication state in Redux.

9. Authentication Payload

interface LoginPayload {
    token: string;
    user: User;
}

The login action can receive both the JWT token and authenticated user information.

10. Exporting Redux Actions

export const {
    login,
    logout
} = authSlice.actions;

These actions can be dispatched from React Native screens or other application logic.

11. Exporting the Reducer

export default
    authSlice.reducer;

The reducer is later added to the Redux store.

12. Creating the Redux Store

import {
    configureStore
} from "@reduxjs/toolkit";

import authReducer
    from "./authSlice";

export const store =
    configureStore({
        reducer: {
            auth: authReducer
        }
    });

13. Adding Provider

import {
    Provider
} from "react-redux";

import {
    store
} from "./store";

const App = () => {

    return (
        <Provider store={store}>

            <AppNavigator />

        </Provider>
    );
};

The Redux Provider makes the store available to the application.

14. useSelector

import {
    useSelector
} from "react-redux";

const user =
    useSelector(
        state => state.auth.user
    );

useSelector reads data from the Redux store.

15. Typed RootState

export type RootState =
    ReturnType<
        typeof store.getState
    >;

This allows TypeScript to understand the structure of the Redux store.

16. Typed useSelector

const user =
    useSelector(
        (state: RootState) =>
            state.auth.user
    );

TypeScript can now provide type checking when accessing authentication state.

17. useDispatch

import {
    useDispatch
} from "react-redux";

const dispatch =
    useDispatch();

useDispatch is used to send actions to the Redux store.

18. Dispatching Login

dispatch(
    login({
        token: response.data.token,
        user: response.data.user
    })
);

After a successful login API response, the token and user can be stored in Redux state.

19. Dispatching Logout

dispatch(
    logout()
);

The logout action clears the authentication state in Redux.

20. Login Screen with Redux

const LoginScreen = () => {

    const dispatch =
        useDispatch();

    const handleLogin =
        async () => {

        const response =
            await api.post(
                "/login.php",
                {
                    email,
                    password
                }
            );

        dispatch(
            login({
                token:
                    response.data.token,
                user:
                    response.data.user
            })
        );
    };

    return (
        <Button
            title="Login"
            onPress={handleLogin}
        />
    );
};

21. Redux and AsyncStorage

Redux state exists in memory. If the application is closed completely, the Redux state normally disappears. AsyncStorage or another persistence mechanism can be used to restore authentication information.

Login
 ↓
Redux State
 +
AsyncStorage
 ↓
App Restart
 ↓
Read Stored Token
 ↓
Restore Redux State

22. Restoring Redux Authentication

const restoreAuth =
    async () => {

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

    if (!token) {
        return;
    }

    try {

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

        dispatch(
            login({
                token,
                user:
                    response.data.user
            })
        );

    } catch {

        await AsyncStorage.removeItem(
            "authToken"
        );

        dispatch(logout());
    }
};

23. Redux Authentication with Axios

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

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

        if (token) {

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

        return config;
    }
);

Axios can read the stored token while Redux manages the application's authentication state.

24. Redux Authentication and Navigation

const RootNavigator = () => {

    const isAuthenticated =
        useSelector(
            (state: RootState) =>
                state.auth.isAuthenticated
        );

    const loading =
        useSelector(
            (state: RootState) =>
                state.auth.loading
        );

    if (loading) {

        return <LoadingScreen />;
    }

    return isAuthenticated
        ? <AppNavigator />
        : <AuthNavigator />;
};

25. Complete Auth Slice

import {
    createSlice,
    PayloadAction
} from "@reduxjs/toolkit";

interface User {
    id: number;
    name: string;
    email: string;
    role: "admin" | "teacher" | "student";
}

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

interface LoginPayload {
    token: string;
    user: User;
}

const initialState: AuthState = {
    user: null,
    token: null,
    isAuthenticated: false,
    loading: true
};

const authSlice =
    createSlice({

    name: "auth",

    initialState,

    reducers: {

        login: (
            state,
            action: PayloadAction<LoginPayload>
        ) => {

            state.user =
                action.payload.user;

            state.token =
                action.payload.token;

            state.isAuthenticated =
                true;

            state.loading =
                false;
        },

        logout: state => {

            state.user = null;
            state.token = null;
            state.isAuthenticated =
                false;
            state.loading =
                false;
        },

        setLoading: (
            state,
            action: PayloadAction<boolean>
        ) => {

            state.loading =
                action.payload;
        }
    }
});

export const {
    login,
    logout,
    setLoading
} = authSlice.actions;

export default
    authSlice.reducer;

26. Complete Redux Store

import {
    configureStore
} from "@reduxjs/toolkit";

import authReducer
    from "./authSlice";

export const store =
    configureStore({
        reducer: {
            auth: authReducer
        }
    });

export type RootState =
    ReturnType<
        typeof store.getState
    >;

export type AppDispatch =
    typeof store.dispatch;

27. Typed Redux Hooks

import {
    useDispatch,
    useSelector
} from "react-redux";

import type {
    RootState,
    AppDispatch
} from "./store";

export const useAppDispatch =
    () => useDispatch<AppDispatch>();

export const useAppSelector =
    useSelector.withTypes<RootState>();

Typed hooks reduce repeated TypeScript annotations when working with Redux.

28. Complete Logout with Redux

const handleLogout = async () => {

    await AsyncStorage.removeItem(
        "authToken"
    );

    dispatch(
        logout()
    );
};

The local credential and Redux authentication state should be cleared together.

29. Redux Authentication Architecture

Login Screen
     ↓
PHP Login API
     ↓
JWT + User
     ↓
Redux Auth Slice
     ↓
┌───────────────┐
│ User          │
│ Token         │
│ Auth Status   │
└───────────────┘
     ↓
AsyncStorage
     ↓
Axios
     ↓
Bearer JWT
     ↓
Protected PHP API
     ↓
JWT Verification

Redux handles the client-side authentication state while the PHP API remains responsible for authentication and authorization.

30. Complete React Native Redux Authentication Flow

Application Starts
       ↓
Redux Provider
       ↓
Restore Stored Token
       ↓
Call Protected Profile API
       ↓
PHP Verifies JWT
       ↓
Valid?
   ↙        ↘
 Yes        No
  ↓          ↓
User Data   Logout
  ↓
Dispatch login()
  ↓
Redux Auth State
  ↓
isAuthenticated = true
  ↓
App Navigator
  ↓
Protected Screens
  ↓
Axios Protected Requests

Logout:
Protected Screen
  ↓
Remove Token
  ↓
Dispatch logout()
  ↓
isAuthenticated = false
  ↓
Auth Navigator

Redux Toolkit, AsyncStorage, Axios, JWT authentication, and React Navigation can work together to create a complete authentication system for a React Native application.

📌 Key Points

  • Redux can centrally manage authentication state.
  • Redux Toolkit simplifies authentication reducers and actions.
  • The auth slice can contain user, token, loading, and authentication status.
  • useSelector reads authentication state.
  • useDispatch sends login and logout actions.
  • Redux state can work together with AsyncStorage for persistent login.
  • Axios can automatically attach the stored JWT.
  • Redux authentication state can control application navigation.
  • Logout should clear both the stored credential and Redux state.
  • Redux does not replace server-side JWT verification or authorization.

🧠 Quick Quiz

Question: Which Redux Toolkit function is commonly used to create an authentication slice?