0
votes

TL;DR: after login JWT is saved in client-side (from auth0lock), when sent to the server side using angular2-jwt, when verified using express-jwt receiving: "UnauthorizedError: jwt malformed"

Hello, I've working on a SPA, the front-end is angular2 and the backend is express, The current feature I'm working on is authentication, after some researching I've figured the best solution would be using Auth0.

I'm using Auth0Lock because I don't like the hosted page, and getting out of the SPA, the problem I'm having is after logining in, I created a button to test that the authentication goes through my server side, and upon clicking on it, I receive "UnauthorizedError: jwt malformed" on the server side.

The flow of my login is client-side only at first, you click the login button, you get the Auth0Lock, you login, and a JWT is saved on the client-side, once you are logged in, when you click the test button, the JWT is passed to the server-side using Angular2-jwt module, and the JWT is verified in the server side.

Client-side auth service:

@Injectable()
export class AuthService {

  private lock: any;
  private userProfile: any;

  constructor(public router: Router) {
    this.lock = new Auth0Lock(AUTH_CONFIG.clientID, AUTH_CONFIG.domain, {
    oidcConformant: true,
    autoclose: true,
    auth: {
      redirectUrl: AUTH_CONFIG.callbackURL,
      responseType: 'token id_token',
      audience: AUTH_CONFIG.audience,
      params: {
        scope: 'openid profile user_metadata email'
      }
    },
    rememberLastLogin: true,
    allowForgotPassword: true,
    languageDictionary: { title: 'Cowoffee'},
    socialButtonStyle: 'small'
  });
  }

  public login(): void {
    this.lock.show();
  }

  // Call this method in app.component
  // if using path-based routing
  public handleAuthentication(): void {
    this.lock.on('authenticated', (authResult) => {
      if (authResult && authResult.accessToken && authResult.idToken) {
        this.setSession(authResult);
        this.router.navigate(['/']);
      }
    });
    this.lock.on('authorization_error', (err) => {
      this.router.navigate(['/']);
      console.log(err);
      alert(`Error: ${err.error}. Check the console for further details.`);
    });
  }

  // Call this method in app.component
  // if using hash-based routing
  public handleAuthenticationWithHash(): void {
    this
      .router
      .events
      .filter(event => event instanceof NavigationStart)
      .filter((event: NavigationStart) => (/access_token|id_token|error/).test(event.url))
      .subscribe(() => {
        this.lock.resumeAuth(window.location.hash, (err, authResult) => {
          if (err) {
            this.router.navigate(['/']);
            console.log(err);
            alert(`Error: ${err.error}. Check the console for further details.`);
            return;
          }
          this.setSession(authResult);
          this.router.navigate(['/']);
        });
    });
  }

  private setSession(authResult): void {
    // Set the time that the access token will expire at
    const expiresAt = JSON.stringify((authResult.expiresIn * 1000) + new Date().getTime());
    localStorage.setItem('access_token', authResult.accessToken);
    localStorage.setItem('id_token', authResult.idToken);
    localStorage.setItem('expires_at', expiresAt);
  }

  public logout(): void {
    // Remove tokens and expiry time from localStorage
    localStorage.removeItem('access_token');
    localStorage.removeItem('id_token');
    localStorage.removeItem('expires_at');
    // Go back to the home route
    this.router.navigate(['/']);
  }

  public isAuthenticated(): boolean {
    // Check whether the current time is past the
    // access token's expiry time
    const expiresAt = JSON.parse(localStorage.getItem('expires_at'));
    return new Date().getTime() < expiresAt;
  }

  public async getProfile(): Promise<any> {
    if (this.userProfile) {
      return this.userProfile;
    }

    const accessToken = localStorage.getItem('access_token');
    if (!accessToken) {
      throw new Error('Access token must exist to fetch profile');
    }
    const test: any = promisifyAll(this.lock);
    this.userProfile = test.getUserInfoAsync(accessToken);
    return this.userProfile;
  }

}

Client-side provider:

export function authHttpServiceFactory(http: Http, options: RequestOptions) {
  return new AuthHttp(new AuthConfig({
    tokenGetter: (() => sessionStorage.getItem('access_token')),
    globalHeaders: [{'Content-Type': 'application/json'}],
  }), http, options);
}

Server-side verification settings:

export const JwtConfiguration = {
  // Dynamically provide a signing key
  // based on the kid in the header and
  // the singing keys provided by the JWKS endpoint.
  secret: jwksRsa.expressJwtSecret({
    cache: true,
    rateLimit: true,
    jwksRequestsPerMinute: 5,
    jwksUri: `https://*******.eu.auth0.com/.well-known/jwks.json`
  }),

  // Validate the audience and the issuer.
  audience: 'https://*******',
  issuer: `https://*******.eu.auth0.com/`,
  algorithms: ['RS256']
};

Servier-side verification inside a controller:

@JsonController('/test')
export class TestController {
    @Get('/')
    @UndefinedResultCode(500)
    @UseBefore(jwt(JwtConfiguration))
    public TestJWT(): string {
        return 'success';
        }
}

I'd like to say that most of this code was copied and used from the Auth0 documentation, thanks alot for the help and sorry for the long post!

UPDATE: The problem was that the token was saved inside the localStorage and I was trying to retreive it from the sessionStorage, rather embarassing, happens when you just copy paste examples... after that everything worked perfectly.

1
The problem was that the token was saved inside the localStorage and I was trying to retreive it from the sessionStorage, rather embarassing, happens when you just copy paste examples... after that everything worked perfectly. - Lopierdis

1 Answers

0
votes

The problem was that the token was saved inside the localStorage and I was trying to retreive it from the sessionStorage, rather embarassing, happens when you just copy paste examples... after that everything worked perfectly.

If anyone is using Auth0, pay attention to the new community, the old are useless, good luck to you all. :)