I have issue passing a token from POST response in auth.service.ts
into a HttpInterceptor and set the token in the authorization header.
As I understand an interceptor runs before any HTTP requests, intercepts, modify and return a cloned version.
But my header isn't getting updated. The interceptor just returns the default value of tokenSubject$
which is null
, before the auth.service have run and the new value of the BehaviorSubject has been emitted.
brower console
interceptor null
auth.service.ts:19 {token: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."}
auth.service.ts:21 eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Raw headers
Host: localhost:3000
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:70.0) Gecko/20100101 Firefox/70.0
Accept: application/json, text/plain, */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: http://localhost:4200/login
Authorization: Bearer null
Content-Type: application/json
Content-Length: 52
Origin: http://localhost:4200
DNT: 1
Connection: keep-alive
How am I supposed to add a token to an Authorization header?
auth.service.ts
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { BehaviorSubject } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class AuthService {
tokenSubject$ = new BehaviorSubject(null);
constructor(private httpClient: HttpClient) {}
login(userEmailAndPassword: { email: string, password: string }) {
return this.httpClient
.post<{ token: string }>('http://localhost:3000/users/login', userEmailAndPassword)
.subscribe(user => {
console.log(user); // { token: "eyJhbGciOiJIUzI..." }
this.tokenSubject$.next(user.token);
console.log(this.tokenSubject$.value); // "eyJhbGciOiJIUzI..."
});
}
}
jwt-interceptor.ts
import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http';
import { Observable } from 'rxjs';
import { Injectable } from '@angular/core';
import { AuthService } from './auth.service';
@Injectable()
export class JwtInterceptor implements HttpInterceptor {
constructor(private authService: AuthService) {}
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
const setAuthorizationToken = req.clone({
headers: req.headers.set('Authorization', `Bearer ${this.authService.tokenSubject$.value}`)
});
console.log('interceptor', this.authService.tokenSubject$.value);
return next.handle(setAuthorizationToken);
}
}
app.module.ts
import { HTTP_INTERCEPTORS, HttpClientModule } from '@angular/common/http';
import { LoginComponent } from './login/login.component';
import { JwtInterceptor } from './jwt-interceptor';
import { RouterModule, Routes } from '@angular/router';
import { UsersComponent } from './users/users.component';
const routes: Routes = [
{path: 'login', component: LoginComponent},
{path: 'signup', component: SignupComponent},
{path: 'users', component: UsersComponent}
];
@NgModule({
declarations: [
AppComponent,
SignupComponent,
LoginComponent,
UsersComponent
],
imports: [
RouterModule.forRoot(routes),
BrowserModule,
HttpClientModule,
ReactiveFormsModule
],
providers: [{provide: HTTP_INTERCEPTORS, useClass: JwtInterceptor, multi: true}],
bootstrap: [AppComponent]
})
export class AppModule {}
HTTP Request
POST http://localhost:3000/users/login
Content-Type: application/json
{
"email": "mr@mr.com",
"password": "myawesomepassword"
}
HTTP Response
POST http://localhost:3000/users/login
HTTP/1.1 200 OK
X-Powered-By: Express
Access-Control-Allow-Origin: *
Content-Type: application/json; charset=utf-8
Content-Length: 209
ETag: W/"d1-MJNo/MXLpxhkX1PE78vlqkKR5GQ"
Date: Wed, 28 Aug 2019 09:07:42 GMT
Connection: keep-alive
{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
Response code: 200 (OK); Time: 15ms; Content length: 209 bytes
You should save the auth token somewhere else than the service, as it is going to be null, everytime the page gets reloaded. I suggest to use localstorage:
login(userEmailAndPassword: { email: string, password: string }) {
return this.httpClient
.post<{ token: string }>('http://localhost:3000/users/login', userEmailAndPassword)
.subscribe(user => {
console.log(user); // { token: "eyJhbGciOiJIUzI..." }
this.tokenSubject$.next(user.token);
localStorage.setItem('token', user.token);// --> Here u are saving the token to localstorage
console.log(this.tokenSubject$.value); // "eyJhbGciOiJIUzI..."
});
}
also u could save the whole user object:
login(userEmailAndPassword: { email: string, password: string }) {
return this.httpClient
.post<{ token: string }>('http://localhost:3000/users/login', userEmailAndPassword)
.subscribe(user => {
console.log(user); // { token: "eyJhbGciOiJIUzI..." }
this.tokenSubject$.next(user.token);
localStorage.setItem('user', JSON.stringify(user));// --> Here u are saving the user to localstorage
console.log(this.tokenSubject$.value); // "eyJhbGciOiJIUzI..."
});
}
to retrieve the user from localstorage u would have to parse it as JSON:
JSON.parse(localStorage.getItem("user"));
then in ur interceptor do this:
const setAuthorizationToken = request.clone({
headers: new HttpHeaders({
'Content-Type': 'application/json',
Authorization: 'Bearer ' + localStorage.getItem('token') === null ? '' : localStorage.getItem('token');
})
});
Usually I write a UserService for retrieving the token/user from the localstorage.
Regards