First implementation of refresh token.

This commit is contained in:
Florian THIERRY
2024-09-03 10:37:58 +02:00
parent be34c555a5
commit 4d44b6f53c
7 changed files with 67 additions and 4 deletions

View File

@@ -2,7 +2,11 @@ application:
pictures:
path: /home/florian/Developpement/codiki-hexagonal/backend/pictures-folder/
temp-path : /home/florian/Developpement/codiki-hexagonal/backend/pictures-folder/temp/
security:
jwt:
expirationDelayInMinutes: 1
refreshToken:
expirationDelayInDays: 7
server:
port: 8987

View File

@@ -0,0 +1,11 @@
meta {
name: Refresh token
type: http
seq: 4
}
post {
url: {{url}}/api/users/refresh-token
body: none
auth: none
}

View File

@@ -8,6 +8,10 @@ export class JwtInterceptor implements HttpInterceptor {
private readonly authenticationService = inject(AuthenticationService);
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
if (this.authenticationService.isTokenExpired()) {
this.authenticationService.renewToken();
}
const jwt = this.authenticationService.getToken();
if (jwt) {
@@ -16,6 +20,8 @@ export class JwtInterceptor implements HttpInterceptor {
});
return next.handle(cloned);
} else {
this.authenticationService.unauthenticate();
}
return next.handle(request);

View File

@@ -0,0 +1,3 @@
export interface RefreshTokenRequest {
refreshTokenValue: string;
}

View File

@@ -3,6 +3,7 @@ import { Injectable, inject } from "@angular/core";
import { LoginRequest, LoginResponse } from "./model/login.model";
import { lastValueFrom } from "rxjs";
import { SigninRequest } from "./model/signin.model";
import { RefreshTokenRequest } from "./model/refresh-token.model";
@Injectable({
providedIn: 'root'
@@ -17,4 +18,8 @@ export class UserRestService {
signin(request: SigninRequest): Promise<void> {
return lastValueFrom(this.httpClient.post<void>('/api/users', request));
}
refreshToken(request: RefreshTokenRequest): Promise<LoginResponse> {
return lastValueFrom(this.httpClient.post<LoginResponse>('/api/users/refresh-token', request));
}
}

View File

@@ -1,7 +1,10 @@
import { Injectable } from "@angular/core";
import { inject, Injectable } from "@angular/core";
import { User } from "../model/User";
import { UserRestService } from "../rest-services/user/user.rest-service";
import { RefreshTokenRequest } from "../rest-services/user/model/refresh-token.model";
const JWT_PARAM = 'jwt';
const REFRESH_TOKEN_PARAM = 'refresh-token';
interface UserDetails {
sub: string;
@@ -15,8 +18,11 @@ interface UserDetails {
providedIn: 'root'
})
export class AuthenticationService {
authenticate(token: string): void {
private userRestService = inject(UserRestService);
authenticate(token: string, refreshToken: string): void {
localStorage.setItem(JWT_PARAM, token);
localStorage.setItem(REFRESH_TOKEN_PARAM, refreshToken);
}
unauthenticate(): void {
@@ -44,6 +50,34 @@ export class AuthenticationService {
return localStorage.getItem(JWT_PARAM) ?? undefined;
}
isTokenExpired(): boolean {
let result = false;
const userDetails = this.extractUserDetails();
if (userDetails) {
const expirationDate = new Date(userDetails.exp * 1000);
const now = new Date();
result = expirationDate < now;
}
return result;
}
renewToken(): void {
const refreshToken = localStorage.getItem(REFRESH_TOKEN_PARAM);
if (refreshToken) {
const request: RefreshTokenRequest = {
refreshTokenValue: refreshToken
};
this.userRestService.refreshToken(request)
.then(refreshTokenResponse => {
this.authenticate(refreshTokenResponse.accessToken, refreshTokenResponse.refreshToken);
});
}
}
private extractUserFromLocalStorage(): User | undefined {
let result: User | undefined = undefined;

View File

@@ -65,7 +65,7 @@ export class LoginService {
this.userRestService
.login(state.request)
.then((response) => {
this.authenticationService.authenticate(response.accessToken);
this.authenticationService.authenticate(response.accessToken, response.refreshToken);
this.snackBar.open('Authentication succeeded!', 'Close', {
duration: 5000,
});