Auth0 Home Blog Docs

Angular SPA Get Access Token to Call API

api
id_token
access_token
access-token
bearer-token

#1

I am creating a new Angular 2+ application that has an ASP.Net Core Web API backend.

I have followed the Angular 2+ quickstart documentation, https://auth0.com/docs/quickstart/spa/angular2, and that is working.

Likewise, for the ASP.Net Core Web API, I followed the quickstart https://auth0.com/docs/quickstart/backend/aspnet-core-webapi which uses the new API section in the dashboard. I successfully tested the web API authorization in isolation using Postman and an access token provided by the Test Client in the Dashboard.

The next step is to make a web API call from the Angular app. It seemed that the best approach is to import AuthHttp, ie:

import { AuthHttp } from 'angular2-jwt/angular2-jwt';

However, AuthHttp get uses id_token in localStorage and this didn’t work. I then discovered that an access_token is needed, not an id_token. I then tried the solution in https://auth0.com/forum/t/lock-not-always-passing-audience/5121/21. I can get an access_token but not an id_token token.

I have read the API Authorization documentation, in particular Calling APIs from Client-side Web Apps, https://auth0.com/docs/api-auth/grant/implicit and I understand the high level principle of what needs to be done.

I would like to know the best practice for using Auth0Lock in an Angular app to authenticate a user but also get an access_token. It seems than an id_token is also needed so that the Angular app can still call tokenNotExpired(). I think that a client app with a Web API would be a common scenario so it would be great if a complete set of instructions for achieving this as I am a bit confused at the moment.

Edit:

Using just responseType: 'token id_token' does return both tokens. However, the access token is only 16 characters and therefore not suitable as a bearer token for calling the API.

https://auth0.com/forum/t/lock-not-always-passing-audience/5121/23 seems to suggest using the following:

 lockOptions = {
        oidcConformant: true,
        autoClose: true,
        auth: {
            params: { audience: 'https://myapi.example.com' }
        }
    };

In this case, a long accessToken is returned and it can be successfully used as a bearer token. However, idToken is undefined. If responseType: 'token id_token' is added, as in the example below, idToken is still undefined.

lockOptions = {
        oidcConformant: true,
        autoClose: true,
        auth: {
            responseType: 'token id_token',
            params: { audience: 'https://myapi.example.com' }
        }
    };

Is there any way to return an idToken as well as a long accessToken?


#2

You can obtain an access_token and an id_token by setting the responseType parameter to:

...
responseType: 'token id_token',
...

In your lock.on('authenticated') event, you can store the id_token to localStorage:

localStorage.setItem('id_token', authResult.idToken);

#3

Did you ever solve this? I have exactly the same problem. Even when adding responseType: 'token id_token', to my options I am only receiving the access token. My options are currently:

private options = {
    responseType: "token id_token",
    auth: {
        params: {
            audience: "http://base.com/api"
        }
    },
    oidcConformant: true,
    autoClose: true
};

#4

@ben1, I completely understand your frustrations and I think you have put it well. I was disappointed with the initial response to my question. Fortunately, I did get it working and thanks for the prompt to share it. I should have shared it earlier. The code snippet does include references to where I found useful information. I hope this works for you.

import { Injectable } from '@angular/core';
import { tokenNotExpired } from 'angular2-jwt';
import { Router } from '@angular/router';

// Avoid name not found warnings
//declare var Auth0Lock: any;
//See https://auth0.com/forum/t/auth0lock-not-defined-in-angular2/3785
let Auth0Lock = require('auth0-lock').default;

@Injectable()
export class Auth {

    // Configure Auth0

    //Need to add openid - https://community.auth0.com/questions/346/how-to-login-in-a-spa-and-obtain-a-token-to-call-i
    //Need to add profile to return profile.

    lockOptions = {
        oidcConformant: true,
        autoclose: true,
        auth: {
            params: {
                audience: 'https://api.example.com.au',
                scope: 'openid profile'
            }
        }
    };

    lock = new Auth0Lock('K7zIH...', 'example.auth0.com', this.lockOptions );

    //Store profile object in auth class
    userProfile: Object;

    constructor(private router: Router) {
        // Set userProfile attribute of already saved profile
        this.userProfile = JSON.parse(localStorage.getItem('profile'));

        // Add callback for lock `authenticated` event
        this.lock.on("authenticated", (authResult) => {

            //https://github.com/auth0/auth0.js/issues/241
            
            localStorage.setItem('id_token', authResult.idToken);

            var accessToken: string = authResult.accessToken;
            localStorage.setItem('access_token', accessToken);

            // Fetch profile information
            //Use getUserInfo as getProfile is deprecated. Also need to pass in accessToken, not idToken.
            this.lock.getUserInfo(accessToken, (error, profile) => {
                if (error) {
                    // Handle error
                    alert(error);
                    return;
                }

                localStorage.setItem('profile', JSON.stringify(profile));
                this.userProfile = profile;
            });

            // Redirect if there is a saved url to do so.
            var redirectUrl: string = localStorage.getItem('redirect_url');
            if (redirectUrl != undefined) {
                this.router.navigate([redirectUrl]);
                localStorage.removeItem('redirect_url');
            }
        });

    }

    public login() {
        // Call the show method to display the widget.
        this.lock.show();
    }

    public authenticated() {
        // Check if there's an unexpired JWT
        // This searches for an item in localStorage with key == 'id_token'
        return tokenNotExpired('id_token');
    }

    public logout() {
        // Remove token from localStorage
        localStorage.removeItem('id_token');
        localStorage.removeItem('access_token');
        localStorage.removeItem('profile');

        this.router.navigate('home']);
    }
}

#5

did you have the callback route configured? My issue was that my app was using # URLs (for use with amazon S3) which do not seem to be supported with Auth0.


#6

Regarding # URLs, this is a bit of a problem with Auth0 and Angular.
It took me a while to work this out. The problem is that the web server must redirect 404’s to the web root and then let angular decode the url.
That is if your angular app is located at http://app.example.com and you make a call to http://app.example.com/anything-else, the web server should redirect you to http://app.example.com.
In my case my server just wouldn’t let me do this so I used Apache to serve the app and adjusted the Apache config appropriately.


#7

Regarding # URLs, this is a bit of a problem with Auth0 and Angular.

It took me a while to work this out. The problem is that the web server must redirect 404’s to the web root and then let angular decode the url.

That is if your angular app is located at http://app.example.com and you make a call to http://app.example.com/anything-else, the web server should redirect you to http://app.example.com.

In my case my server just wouldn’t let me do this so I used Apache to serve the app and adjusted the Apache config appropriately.


#8

Did you ever solve this? I have exactly the same problem. Even when adding responseType: 'token id_token', to my options I am only receiving the access token. My options are currently:

private options = {
    responseType: "token id_token",
    auth: {
        params: {
            audience: "http://base.com/api"
        }
    },
    oidcConformant: true,
    autoClose: true
};

#9

I’ve been tearing my hair out trying to integrate Auth0 with an Angular 2 front end application that calls through to a .NET core API. Getting Auth0 working on the frontend was relatively straight forward but getting it to play nicely with the API has been incredibly frustrating - so much so that I am on the verge of abandoning Auth0 altogether. Whilst there seems to be a glut of docs, trying to get what I imagine is a fairly standard use case working has been a nightmare.

This https://auth0.com/docs/api-auth/tutorials/implicit-grant makes no mention of Lock, are the two incompatible?


#10