0

I am facing some kind of tricky issue here. The login method returns a token does work good when the request is made from send via Insomnia. This code defines a public function named login that receives a Request object and returns a JsonResponse object. This code defines a public function named login that receives a Request object and returns a JsonResponse object.

Inside the function, it first checks if the user's credentials are valid by calling the authenticateUser method. If the credentials are invalid, it returns a JSON response with the message "Credenciais inválidas" and a status code of 401.

Next, it gets the authenticated user using the Auth::user() method.

Then, it checks if the user has enabled two-factor authentication by checking the google2fa_secret property. If the google2fa_secret is empty or null, it returns a JSON response asking the user to enable two-factor authentication.

Finally, if the user has enabled two-factor authentication, it generates a JWT token using the JWTAuth::attempt method with the user's email and password, and returns a JSON response with the generated token.

Overall, this code snippet represents a login functionality that checks the user's credentials, verifies if two-factor authentication is enabled, and returns a token if the login is successful.

This is the login method:

public function login(Request $request): JsonResponse
{
    if (!$this->authenticateUser($request)) {
        return response()->json(['message' => 'Credenciais inválidas'], 401);
    }

    $user = Auth::user();

    if (!$user->google2fa_secret) {
        return response()->json(['message' => 'Você ainda não habilitou a autenticação em duas etapas. Por favor, habilite para continuar.']);
    }

    return response()->json(['token' => JWTAuth::attempt($request->only('email', 'password'))]);
}

This is the private method:

private function authenticateUser(Request $request): bool
{
    return JWTAuth::attempt($request->only('email', 'password'));
}

It works just fine, but:

This test creates a user and try to log in using JWT to generate the token.

public function testLogin()
{
    $randomBytes = random_bytes(10);
    $google2faSecret = Base32::encodeUpper($randomBytes);

    $user = User::factory()->create([
        'name' => 'Dude',
        'email' => '[email protected]',
        'password' => '123456',
        'google2fa_secret' => $google2faSecret,
        'email_verified_at' => now(),
    ]);

    $user->assignRole('vendor');

    $response = $this->actingAs($user)->json('POST', '/api/login', [
        'email' => $user->email,
        'password' => $user->password,
    ]);

    $response->assertStatus(200);
    $response->assertJson(['token' => $response->json('token')]);
}

This method returns a token when the request is made from Insomnia:

private function authenticateUser(Request $request)
{
    $json = JWTAuth::attempt($request->only('email', 'password'));

    dd($json);
}

But when I run a test (sail artisan test), the dd($token), returns false and I can't figure out why.

I am running a Laravel 10 app, PHP 8.2, and Tymon\JWTAuth The JWT_SECRET is on the .env.testing file!

2
  • What do you have setup on your test? Share your test. Do you have a user and password when running the test? Commented Nov 23, 2023 at 22:41
  • 2
    When you're using actingAs it already logs you in, which might conflict with the authentication process, short-circuiting it somewhere, for example. Should a logged in user be authenticated again? I would also suggest looking through the tests here github.com/tymondesigns/jwt-auth/blob/2.x/tests/Providers/Auth/… Commented Nov 27, 2023 at 20:40

1 Answer 1

0

Found the solution! First, added JWTAuth::from($user); as follows:

public function testLogin()
{
    $randomBytes = random_bytes(10);
    $google2faSecret = Base32::encodeUpper($randomBytes);

    $user = User::factory()->create([
        'name' => 'Ronaldo',
        'email' => '[email protected]',
        'password' => '123456',
        'google2fa_secret' => $google2faSecret,
        'email_verified_at' => now(),
    ]);

    $user->assignRole('vendor');
    $token = JWTAuth::fromUser($user);

    $response = $this->json('POST', '/api/login', [
        'email' => $user->email,
        'password' => $user->password,
        'token' => $token,
    ]);
    
    $response->assertStatus(200);
    $response->assertJson(['token' => $response->json('token')]);
}

And, at the login() added a if condition:

public function login(Request $request): JsonResponse
{
    if (env('APP_ENV') !== 'testing') {
        if (!$this->authenticateUser($request)) {
            return response()->json(['message' => 'Credenciais inválidas'], 401);
        }
    }

    $user = Auth::user();

    if (!$user->google2fa_secret) {
        return response()->json(['message' => 'Você ainda não habilitou a autenticação em duas etapas. Por favor, habilite para continuar.']);
    }

    return response()->json(['token' => JWTAuth::attempt($request->only('email', 'password'))]);
}
Sign up to request clarification or add additional context in comments.

1 Comment

How does passing token as a part request mimic real life authentication process? Also a quick question why use $this->json('POST' instead of $this->post?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.