Search code examples
laravelreact-nativecsrf-token

Token mismatch using react native with laravel breeze


I'm trying to convert a react project to react native but am having trouble with authentication. The back-end is Laravel with the Breeze kit to provide authentication. I managed to get the token from laravel-sanctum by adding a route to the api per the Laravel documentation for authenticating mobile apps.

Route::post('/sanctum/token', function (Request $request) {
    $request->validate([
        'email' => 'required|email',
        'password' => 'required',
        'device_name' => 'required',
    ]);

    $user = User::where('email', $request->email)->first();

    if(!$user || !Hash::check($request->password, $user->password)) {
        throw ValidationException::withMessages([
            'email' => ['The provided credentials are incorrect'],
        ]);
    }

    return $user->createToken($request->device_name)->plainTextToken;
});

Then I hit post to this route with the login details

try {
    const response = await axios.post('http://192.168.1.105:8000/api/sanctum/token', {
        email: email,
        password: password,
        device_name: 'mobile',
    });

    const csrfToken = response.data;
    axios.defaults.headers.common['X-XSRF-TOKEN'] = csrfToken;
} catch (error) {
    console.log(error);
    Alert.alert('Login Failed', 'Please check your credentials and try again.');
}

I can see the token in the response, so that part looks good.

Then I created a logout action on the client

const response = await axios.post('http://192.168.1.105:8000/logout', {});

I can see the X-XSRF-TOKEN and XSRF-TOKEN cookie being included in the header, but I get a token mismatch error. In case the standard 'logout' route isn't designed for mobile apps, I've also tried to create a new route for logout in the back-end.

Route::middleware('auth:sanctum')->group(function () {
    Route::post('/sanctum/logout', [AuthenticatedSessionController::class, 'logout']);
});

Now I get unauthenticated. My .env has APP_URL=192.168.1.105:8000 and config/sanctum.php has

'stateful' => explode(',', env('SANCTUM_STATEFUL_DOMAINS', sprintf(
    '%s%s',
    'localhost,localhost:3000,127.0.0.1,127.0.0.1:8000,::1, 192.168.1.105:3000, 192.168.1.105:8000',
    Sanctum::currentApplicationUrlWithPort()
))),

These two usually fix problems I have when I get 'unauthenticated' from a SPA, but they haven't helped here. I'm not sure what else to try.


Solution

  • I missed a line in the Laravel Sanctum docs, which says When the mobile application uses the token to make an API request to your application, it should pass the token in the Authorization header as a Bearer token.

    After some digging around, I worked out that I needed to change

    axios.defaults.headers.common['X-XSRF-TOKEN'] = csrfToken;
    

    to

    axios.defaults.headers.common['Authorization'] = `Bearer ${csrfToken}`;
    

    After making that change, laravel recognises the session.