Here I am working on integrating JWT in Angular with a .Net Core API. When I start my Angular server and launch the application, I encounter the following scenarios:
- Attempting with correct credentials initially fails, but retrying allows it to work.
- Trying with incorrect credentials at first fails, then retrying again causes failure again.
- Starting with correct credentials fails, trying again with incorrect ones leads to successful login.
I want to clarify that the success of logging in depends on the JWT token already being stored in localStorage as a value. This means that at a certain point, the API call works; it's just not validated correctly at the right time for some reason.
To dig deeper into this issue, here is the relevant code snippet:
This is the AuthService component:
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { User } from 'src/app/models/User';
const httpOptions = {
headers: new HttpHeaders({
'Content-Type':'application/json;charset=UTF-8'
})
}
@Injectable({
providedIn: 'root'
})
export class AuthService{
public loggedIn = false;
constructor(private httpClient:HttpClient) { }
login(user: User){
// Set the User object with the corresponding credentials as the request body
const body = JSON.stringify(user);
// Send the post request with its corresponding headers and body
this.httpClient.post<any>("https://localhost:7054/login", body, httpOptions)
.subscribe(data => {
// Here, the data received from the API is known (as I developed it myself):
// it will only contain the token if successful, and will return a bad request
// with a blank token if it fails, so the only scenario where the token may
// be valid is through a HTTP 200 response.
localStorage.setItem("token", data.token);
});
}
}
And this is the HomeComponent.ts file:
import { Component } from '@angular/core';
import { Router } from '@angular/router';
import { AuthResponse } from 'src/app/models/AuthResponse';
import { User } from 'src/app/models/User';
import Swal from "sweetalert2";
import { AuthService } from 'src/app/services/auth/auth.service';
@Component({
selector: 'app-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.css']
})
export class HomeComponent {
user: User = new User();
constructor(private router: Router, private authService:AuthService) {
}
token: AuthResponse = new AuthResponse();
//Login method
login(username: string, password: string) {
// - User authentication
// The verification occurs in the backend for security purposes.
// Validate credentials are not blank
if(username != "" || password != ""){
// Create a new User object, which will be passed to the API as request body
let user = new User();
user.email = username;
user.pass = password;
// Call the auth service
this.authService.login(user);
// If the previous operation went well, the token must be stored, and we should be able to log in
if(localStorage.getItem("token")){
this.router.navigate(['/home']);
}
// If the request returns nothing, the credentials are incorrect, therefore an error alert will be sent, plus the token is set to blank
else{
this.sendError("Credentials are incorrect.")
localStorage.setItem("token", "");
}
}
else{
// If the credentials are blank, therefore an error alert will be sent, plus the token is set to blank
this.sendError("Please type your credentials.")
localStorage.setItem("token", "");
}
}
sendError(error:string){
Swal.fire({
icon: 'error',
title: 'Error',
text: error,
})
}
}
If someone could offer insight into why this unexpected behavior is occurring, I would greatly appreciate it. There seems to be something missing or incorrect in my implementation, but I can't pinpoint it.
Thank you for any assistance provided.
I've attempted using interceptors to handle the response but they haven't resolved the issue related to the strange behavior.
I've also tried enforcing token validation, but it doesn't seem to have an impact since the token appears to get cached between attempts.