12

I am working with JWT (JSON Web Tokens) as a part of logging people into the system. The code that does this is as follows:

this.http.post(url, JSON.stringify({ username: username, password: password }), { observe: 'response' })
      .subscribe((response: HttpResponse<any>) => {

When sending the username and password to the server, the Response object contains the encrypted authorization in the Header.

Included as part of the headers is an Authorization entry and also a Pragma entry. The Authorization has the token correctly defined (and it works). Pragma is also defined as no-cache

From Network tab in Chrome:

enter image description here

but when running the code to process the response headers, the Authorization header is not present.

 adminLogin(username, password) {
    let url = `${this._apiRoot}/login`;
    let tokenResp = {};

    this.http.post(url, JSON.stringify({ username: username, password: password }), { observe: 'response' })
      .subscribe((response: HttpResponse<any>) => {

        console.log(" ---- begin response ----");
        console.log( response );
        console.log(" ---- end response ----");

        let token = response.headers.get("Authorization");

        console.log(" ---- begin token ----");
        console.log ( token );
        console.log(" ---- end token ----");

        let pragma = response.headers.get("pragma");

        console.log(" ---- begin pragma ----");
        console.log ( pragma );
        console.log(" ---- end pragma ----");

Results from code executed:

enter image description here

From the code executed, one can see that the trying to find the Authorization returns null while Pragma gets no-cache. What is going on?

UPDATE

Thanks all for the information.

I followed the information here: https://github.com/angular/angular/issues/13554

and made changes to the java code:

@Override
    protected void successfulAuthentication(HttpServletRequest req,
            HttpServletResponse res, FilterChain chain, Authentication auth)
            throws IOException, ServletException {
        String username = ((User) auth.getPrincipal()).getUsername();
        ApplicationUser user = applicationUserRepository
                .findByUsername(username);

        String token = Jwts
                .builder()
                .setSubject(((User) auth.getPrincipal()).getUsername())
                .claim("id", user.getId())

            [... snip ...]

            res.addHeader("Access-Control-Expose-Headers", "Authorization");
            res.addHeader(SecurityConstants.HEADER_STRING,SecurityConstants.TOKEN_PREFIX + token);

    }

Thanks again!

5
  • 3
    That header isn't allowed to be exposed to the code, you need to set Access-Control-Expose-Headers; see e.g. stackoverflow.com/a/43010215/3001761 Commented Feb 13, 2018 at 23:22
  • 2
    See github.com/angular/angular/issues/20554. You must allow the headers using Access-Control-Expose-Headers Commented Feb 13, 2018 at 23:24
  • Also note you don't have to JSON.stringify the body yourself, and you can use object shorthand notation to write e.g. { username, password }. Another related Q: stackoverflow.com/q/42306684/3001761 Commented Feb 13, 2018 at 23:26
  • you can post your "update" as an answer. Make it easyer for other people to see it Commented Nov 23, 2018 at 18:57
  • Suppose I don't want to expose headers. How am I supposed to store the token on the client side or send authenticated requests if the token came in on an Authorization header? Commented Mar 26, 2019 at 19:16

2 Answers 2

4

To solve this issue we need to expose the desired header from the backend side and use and write a custom HttpInterceptor.

NodeJs API exemple: Expose authorization header from backend

res.setHeader('Access-Control-Expose-Headers', 'authorization'); 
res.setHeader('authorization', 'foo-bar');

Sample angular interceptor

@Injectable()
export class HttpInterceptorService implements HttpInterceptor {
  intercept(request: HttpRequest<any>, next: HttpHandler): Observable<any> {
    return next.handle(request).pipe(
      tap(response => {
        if (response.headers) {
          console.log('Header keys', response.headers.keys());
          console.log('Authorization: ', response.headers.get('authorization'));
        }
      }),
    );
  }
}

Lastly we add our interceptor to our module providers

import { NgModule } from '@angular/core';
import { HTTP_INTERCEPTORS } from '@angular/common/http';
import { HttpInterceptorService } from './http-interceptor.service';

@NgModule({
  ...
  providers: [
    { provide: HTTP_INTERCEPTORS, useClass: HttpInterceptorService, multi: true },
  ],
})
export class AppModule {}

This sample code and repos can be usefull to know more about Angular HttpInterceptor

Sign up to request clarification or add additional context in comments.

Comments

-1
const options = {
        headers: new HttpHeaders({
            'Content-Type': 'application/json',
            Authorization: 'Bearer ' + token
        })
    };
    const requestPayload = ({
        user_type: userType
    });
    return this.http.post<UserModel>(`${API_BASE_URL}/user/${uid}`, JSON.stringify(requestPayload), options);

the above should work fine if you don't want to use the interceptor method, do not that for a post method needs 3 arguments to work in this case: endpoiontURL | requestBody | headerOptions

1 Comment

this doesn't answer the question about how to read the token from the http response

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.