Auth0 Home Blog Docs

Ionic 2 Authorization Code Grant Flow with PKCE

angular-2
authorization-code-f
pkce
ionic2

#1

I started with the Ionic 2+ Auth0 sample project found in the URL below.
https://auth0.com/docs/quickstart/native/ionic2/01-login#display-profile-data

The app uses Auth0.js v8 and the method webAuth.authorize() to get an id_token and user information after log in on our hosted web page. Now I’m trying to implement the PKCE and I don’t see code_challenge or code_challenge_method options in any of the Auth0.js v8 SDK authorize methods. Also, when adding an audience as an optional parameter I get a 401 response. (My client is set up as a Native application)

Am I using the SDK incorrectly? Is it recommended to do things manually like in the PKCE example below? If so, what is the purpose of the Auth0.js v8 SDK and Cordova?
https://auth0.com/docs/api-auth/tutorials/authorization-code-grant-pkce


#2

I may just be confused. Is the Authorization Code Grant strictly for API access? When a user logs in to our mobile app they would hit our auth0 domain to validate their username and password. After that we would then start the Authorization Code Grant process for the API that they’re trying to hit?


#3

The quickstart you linked to uses Auth0.js (v8) and auth0-cordova libraries. The current quickstart code then calls client.authorize from auth0-cordova (which has built-in support for doing PKCE) and does not call the authorize method of Auth0.js (v8). In practice the Auth0.js (v8) library is only used to perform the call to the /userinfo endpoint after the authentication and authorization transaction has completed and the client application already has the tokens (which were obtained through PKCE due to the usage of auth0-cordovalibrary).

You mention that you get a 401, but only when adding an audience parameter. This suggests that the source of the 401 is the code is trying to perform a /userinfo call with an unsuitable access token. More specifically, given it stops working when adding the audience then the API associated with the audience identifier being added is probably using HS256 as the signing algorithm.

When doing both an authentication (according to OpenID Connect) and an authorization request (aka you also include an audience parameter for the authorize endpoint) in a single go the issued access token can have multiple audiences/purposes depending on configuration. If the requested audience uses RS256 the access token will be issued with multiple audiences, one that allows to call the /userinfo endpoint and the other targeting your own API. If the API uses HS256 then the /userinfo endpoint cannot be called because the access token will only include your own API as an audience.

In conclusion, if you want to call /userinfo and your own API and perform a single request then the API needs to use RS256 so that the issued access token is multi-purpose.


#4

I’m also using PKCE following: https://auth0.com/docs/quickstart/native/ionic2/01-login
It first calls /authorize and then /oauth/token to get the acccess token. It works, but I cannot obtain the access token I need to access my API. When calling /oauth/token:
![request][1]
I get a short access token:
![token][2]
Why don’t I get the three parts token as described in: https://auth0.com/docs/tokens/access-token


#5

I’ve had to send the audience with the first request! I’ve added the audience to the /authorize request and now I get the normal access_token from the /oauth/token request! Maybe it’s an good idea to write about it in the Ionic 2 Auth0 tutorial @jmangelo


#6

I’m also using PKCE following: https://auth0.com/docs/quickstart/native/ionic2/01-login
It first calls /authorize and then /oauth/token to get the acccess token. It works, but I cannot obtain the access token I need to access my API. When calling /oauth/token:
![request][1]
I get a short access token:
![token][2]
Why don’t I get the three parts token as described in: https://auth0.com/docs/tokens/access-token


#7

I’ve had to send the audience with the first request! I’ve added the audience to the /authorize request and now I get the normal access_token from the /oauth/token request! Maybe it’s an good idea to write about it in the Ionic 2 Auth0 tutorial @jmangelo


#8

@akselon thanks for the feedback, some of the quickstarts still only show user authentication (login) and don’t have steps specific to obtaining access tokens to call your own API’s. Having more complete quickstarts is something that is indeed on the backlog so hopefully additional information will be available in the future.


#9

@jmangelo @akselon
I am also facing the same behavior. I am getting a short token and not the three parts token as described in: https://auth0.com/docs/tokens/access-token.

How did you resolve this?
Please suggest


Question on having one application with multiple application types
#10

@rakesh_agrawal the Quickstart for Ionic 2 is deleted from Auth0 pages. Anyways, I’ve had to send the audience with the first request. I’ve done it like that (see : 5th line)

    public login() {
        const client = new Auth0Cordova(auth0Config);
        const options = {
            scope: 'openid profile email offline_access',
            audience: 'https://' + auth0Config.domain + '/api/v2/'
        };

        client.authorize(options, (err, authResult) => {
            if(err) {
                console.warn(err);
                (<any>window).SafariViewController.hide();
            } else {

                this.setIdToken(authResult.idToken);
                this.setAccessToken(authResult.accessToken);

                const expiresAt = JSON.stringify((authResult.expiresIn * 1000) + new Date().getTime());
                this.setStorageVariable('expires_at', expiresAt);

                this.auth0.client.userInfo(this.accessToken, (err, profile) => {
                    if (err) {
                        throw err;
                    }

                    profile.user_metadata = profile.user_metadata || {};
                    this.setStorageVariable('profile', profile);
                    this.zone.run(() => {
                        this.user = profile;
                        this.userLoggedIn();
                    });

                });
            }
        });
    }

#11