Skip to content

Commit

Permalink
refactor: set jwt token to a cookie instead of localStorage
Browse files Browse the repository at this point in the history
  • Loading branch information
stefanoslig committed Dec 18, 2024
1 parent 2127c1d commit a163409
Show file tree
Hide file tree
Showing 15 changed files with 46 additions and 115 deletions.
2 changes: 0 additions & 2 deletions apps/conduit/src/app/app.component.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import { AppComponent } from './app.component';
import { RouterTestingModule } from '@angular/router/testing';
import { FooterComponent } from './layout/footer/footer.component';
import { NavbarComponent } from './layout/navbar/navbar.component';
import { LocalStorageJwtService } from '@realworld/auth/data-access';

describe('AppComponent', () => {
let component: AppComponent;
Expand All @@ -14,7 +13,6 @@ describe('AppComponent', () => {
TestBed.configureTestingModule({
imports: [RouterTestingModule],
declarations: [AppComponent, FooterComponent, NavbarComponent],
providers: [LocalStorageJwtService],
}).compileComponents();
}));

Expand Down
18 changes: 5 additions & 13 deletions apps/conduit/src/app/app.component.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { ChangeDetectionStrategy, Component, OnInit, inject } from '@angular/core';
import { ChangeDetectionStrategy, Component, inject } from '@angular/core';
import { RouterModule } from '@angular/router';
import { AuthStore, LocalStorageJwtService } from '@realworld/auth/data-access';
import { filter, take } from 'rxjs/operators';
import { AuthStore } from '@realworld/auth/data-access';
import { FooterComponent } from './layout/footer/footer.component';
import { NavbarComponent } from './layout/navbar/navbar.component';

Expand All @@ -11,17 +10,10 @@ import { NavbarComponent } from './layout/navbar/navbar.component';
imports: [FooterComponent, NavbarComponent, RouterModule],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class AppComponent implements OnInit {
private readonly localStorageJwtService = inject(LocalStorageJwtService);
export class AppComponent {
protected readonly authStore = inject(AuthStore);

ngOnInit() {
this.localStorageJwtService
.getItem()
.pipe(
take(1),
filter((token) => !!token),
)
.subscribe(() => this.authStore.getUser());
constructor() {
this.authStore.getUser();
}
}
4 changes: 2 additions & 2 deletions apps/conduit/src/app/app.config.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { ApplicationConfig, provideExperimentalZonelessChangeDetection } from '@angular/core';
import { provideRouter, withComponentInputBinding, withViewTransitions } from '@angular/router';
import { authGuard, tokenInterceptor } from '@realworld/auth/data-access';
import { authGuard } from '@realworld/auth/data-access';
import { errorHandlingInterceptor } from '@realworld/core/error-handler';
import { provideHttpClient, withInterceptors } from '@angular/common/http';
import { API_URL } from '@realworld/core/http-client';
Expand Down Expand Up @@ -50,7 +50,7 @@ export const appConfig: ApplicationConfig = {
withViewTransitions(),
withComponentInputBinding(),
),
provideHttpClient(withInterceptors([errorHandlingInterceptor, tokenInterceptor])),
provideHttpClient(withInterceptors([errorHandlingInterceptor])),
{ provide: API_URL, useValue: environment.api_url },
],
};
2 changes: 1 addition & 1 deletion apps/conduit/src/environments/environment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@

export const environment = {
production: false,
api_url: 'https://real-world-app-39656dff2ddc.herokuapp.com/api',
api_url: 'http://localhost:3000/api',
};
3 changes: 1 addition & 2 deletions libs/auth/data-access/src/auth.store.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,12 @@ import { HttpClientTestingModule } from '@angular/common/http/testing';
import { inject, TestBed } from '@angular/core/testing';

import { AuthStore } from './auth.store';
import { LocalStorageJwtService } from './services/local-storage-jwt.service';

describe('AuthStore', () => {
beforeEach(() => {
TestBed.configureTestingModule({
imports: [HttpClientTestingModule],
providers: [AuthStore, LocalStorageJwtService, ApiService],
providers: [AuthStore, ApiService],
});
});

Expand Down
32 changes: 16 additions & 16 deletions libs/auth/data-access/src/auth.store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import { inject } from '@angular/core';
import { AuthService } from './services/auth.service';
import { exhaustMap, pipe, switchMap, tap } from 'rxjs';
import { tapResponse } from '@ngrx/operators';
import { LocalStorageJwtService } from './services/local-storage-jwt.service';
import { Router } from '@angular/router';
import { LoginUser, NewUser, User } from '@realworld/core/api-types';
import { setLoaded, withCallState } from '@realworld/core/data-access';
Expand All @@ -15,13 +14,7 @@ export const AuthStore = signalStore(
{ providedIn: 'root' },
withState<AuthState>(authInitialState),
withMethods(
(
store,
formErrorsStore = inject(FormErrorsStore),
authService = inject(AuthService),
localStorageService = inject(LocalStorageJwtService),
router = inject(Router),
) => ({
(store, formErrorsStore = inject(FormErrorsStore), authService = inject(AuthService), router = inject(Router)) => ({
getUser: rxMethod<void>(
pipe(
switchMap(() => authService.user()),
Expand All @@ -35,7 +28,6 @@ export const AuthStore = signalStore(
tapResponse({
next: ({ user }) => {
patchState(store, { user, loggedIn: true });
localStorageService.setItem(user.token);
router.navigateByUrl('/');
},
error: ({ error }) => formErrorsStore.setErrors(error.errors),
Expand All @@ -51,7 +43,6 @@ export const AuthStore = signalStore(
tapResponse({
next: ({ user }) => {
patchState(store, { user, loggedIn: true });
localStorageService.setItem(user.token);
router.navigateByUrl('/');
},
error: ({ error }) => formErrorsStore.setErrors(error.errors),
Expand All @@ -67,7 +58,6 @@ export const AuthStore = signalStore(
tapResponse({
next: ({ user }) => {
patchState(store, { user });
localStorageService.setItem(user.token);
router.navigate(['profile', user.username]);
},
error: ({ error }) => formErrorsStore.setErrors(error.errors),
Expand All @@ -76,11 +66,21 @@ export const AuthStore = signalStore(
),
),
),
logout: () => {
patchState(store, { user: initialUserValue, loggedIn: false });
localStorageService.removeItem();
router.navigateByUrl('login');
},
logout: rxMethod<void>(
pipe(
exhaustMap(() =>
authService.logout().pipe(
tapResponse({
next: () => {
patchState(store, { user: initialUserValue, loggedIn: false });
router.navigateByUrl('login');
},
error: ({ error }) => formErrorsStore.setErrors(error.errors),
}),
),
),
),
),
}),
),
withCallState({ collection: 'getUser' }),
Expand Down
2 changes: 0 additions & 2 deletions libs/auth/data-access/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
export * from './services/token-interceptor.service';
export * from './services/local-storage-jwt.service';
export * from './services/auth-guard';

export { AuthStore } from './auth.store';
2 changes: 1 addition & 1 deletion libs/auth/data-access/src/services/auth-guard.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ describe('authGuard', () => {
});

it('should return login urlTree if the user is not logged in', () => {
jest.spyOn(storage, 'getItem').mockImplementationOnce(() => of(null));
jest.spyOn(storage, 'getItem').mockImplementationOnce(() => null);

const result = TestBed.runInInjectionContext(() => authGuard());

Expand Down
22 changes: 8 additions & 14 deletions libs/auth/data-access/src/services/auth-guard.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,14 @@
import { inject } from '@angular/core';
import { map, Observable, take } from 'rxjs';
import { Router, UrlTree } from '@angular/router';
import { AuthStore } from '../auth.store';

import { LocalStorageJwtService } from './local-storage-jwt.service';

export const authGuard = (): Observable<boolean | UrlTree> => {
const storage = inject(LocalStorageJwtService);
export const authGuard = (): boolean | UrlTree => {
const router = inject(Router);
const authStore = inject(AuthStore);

if (!authStore.loggedIn()) {
return router.parseUrl('/login');
}

return storage.getItem().pipe(
map((token) => {
if (!token) {
return router.parseUrl('/login');
}
return true;
}),
take(1),
);
return true;
};
3 changes: 1 addition & 2 deletions libs/auth/data-access/src/services/auth.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,12 @@ import { HttpClientTestingModule } from '@angular/common/http/testing';
import { inject, TestBed } from '@angular/core/testing';

import { AuthService } from './auth.service';
import { LocalStorageJwtService } from './local-storage-jwt.service';

describe('AuthService', () => {
beforeEach(() => {
TestBed.configureTestingModule({
imports: [HttpClientTestingModule],
providers: [AuthService, LocalStorageJwtService, ApiService],
providers: [AuthService, ApiService],
});
});

Expand Down
4 changes: 4 additions & 0 deletions libs/auth/data-access/src/services/auth.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ export class AuthService {
return this.apiService.post<UserResponse, LoginUserRequest>('/users/login', { user: credentials });
}

logout(): Observable<{ message: string }> {
return this.apiService.post<{ message: string }, void>('/users/logout');
}

register(credentials: NewUser): Observable<UserResponse> {
return this.apiService.post<UserResponse, NewUserRequest>('/users', { user: credentials });
}
Expand Down
23 changes: 0 additions & 23 deletions libs/auth/data-access/src/services/local-storage-jwt.service.ts

This file was deleted.

This file was deleted.

20 changes: 0 additions & 20 deletions libs/auth/data-access/src/services/token-interceptor.service.ts

This file was deleted.

8 changes: 7 additions & 1 deletion libs/core/http-client/src/lib/api.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,22 +12,28 @@ export class ApiService {
return this.http.get<T>(`${this.api_url}${url}`, {
headers: this.headers,
params,
withCredentials: true,
});
}

post<T, D>(url: string, data?: D): Observable<T> {
return this.http.post<T>(`${this.api_url}${url}`, JSON.stringify(data), { headers: this.headers });
return this.http.post<T>(`${this.api_url}${url}`, JSON.stringify(data), {
headers: this.headers,
withCredentials: true,
});
}

put<T, D>(url: string, data: D): Observable<T> {
return this.http.put<T>(`${this.api_url}${url}`, JSON.stringify(data), {
headers: this.headers,
withCredentials: true,
});
}

delete<T>(url: string): Observable<T> {
return this.http.delete<T>(`${this.api_url}${url}`, {
headers: this.headers,
withCredentials: true,
});
}

Expand Down

0 comments on commit a163409

Please sign in to comment.