New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Authorization Code Grant Flow with PKCE #16

Open
ryanmr opened this Issue Feb 1, 2018 · 6 comments

Comments

Projects
None yet
4 participants
@ryanmr

ryanmr commented Feb 1, 2018

Hey there, I'd like to request input or discussion on using Auth0's PKCE flow that allows for a refresh token in addition to the standard id token and access token.

The standard Implicit flow works fine, as demonstrated in the example code. This flow is important in mobile applications, and example here would be extremely valuable and helpful for those using the Expo flavor of React Native and integrating with Auth0. Their documentation makes use of the Node crypto library, which appears to be unavailable in a React Native app.

@BenjaminWatts

This comment has been minimized.

BenjaminWatts commented Feb 9, 2018

any luck with this - I am not sure how to use the access token provided as it doesn't look like a full JSON token - and the documentation seems to be quite lacking on this front - any ideas?

@ryanmr

This comment has been minimized.

ryanmr commented Feb 9, 2018

Hi @BenjaminWatts. Your issue may be unrelated to the lack of support of crypto as noted above.

At least with Auth0, my understanding is: to get a JWT access_token back, you need to supply an audience matching your API audience value when you make your initial /authorize request. Without the audience, Auth0 seems to return a generic access token, rather than a JWT access_token.

@zth

This comment has been minimized.

zth commented Oct 14, 2018

I'm also very interested in this. Has anyone gotten this working in a reasonable way?

@mo

This comment has been minimized.

mo commented Oct 15, 2018

@zth If you have access to a high quality random number source (which afaik is not available in non-ejected expo), you can do something like this:

    const redirectUrl = AuthSession.getRedirectUrl();
    const verifier = base64URLEncode(randomBytes(32));
    const challenge = createChallenge(verifier);
    const result = await AuthSession.startAsync({
      authUrl:
        `${auth0Domain}/authorize` +
        toQueryString({
          audience: "https://some.hostname.com/some/api/url",
          client_id: auth0ClientId,
          response_type: "code",
          scope: "openid profile email",
          code_challenge: challenge,
          code_challenge_method: "S256",
          redirect_uri: redirectUrl,
          connection: "optional-id-for-connection-that-will-be-preselected-auth0-lock-screen"
        })
    });

    if (result.type !== "success") {
      throw Error(
        `result.type was ${
          result.type
        } instead of "success", full result was: ${JSON.stringify(
          result,
          null,
          2
        )}`
      );
    }
    const code = result.params.code;
    const body = {
      grant_type: "authorization_code",
      client_id: auth0ClientId,
      code_verifier: verifier,
      code,
      redirect_uri: redirectUrl
    };
    const resp = await fetch("https://some.host.domain.com/oauth/token", {
      method: "POST",
      headers: {
        "Content-Type": "application/json"
      },
      body: JSON.stringify(body)
    });
    const respJson = await resp.json();
    console.log("respJson=", JSON.stringify(respJson, null, 2));
    const token: IJwtAccessToken = jwtDecoder(respJson.access_token);
    console.log("token=", JSON.stringify(token, null, 2));
    const email = token.sub.split("|")[1];
@ryanmr

This comment has been minimized.

ryanmr commented Oct 16, 2018

To follow up on this, for what it's worth, we decided to make use of a public endpoint that would return the verifier and challenge.

We have an express endpoint serve the following. It's not great, but works for now. Most of our users only ever log in once.

const verifier = base64.encode(crypto.randomBytes(32))
const challenge = base64.encode(sha256(verifier))
return {
  verifier,
  challenge
}
@zth

This comment has been minimized.

zth commented Oct 17, 2018

Thank you for the responses! I ended up doing the same thing, exposing an endpoint for the challenge/verifier. I think expo is working on supporting a native crypto module that can get safe random numbers, so I'll migrate to that whenever that's available. But the endpoint is fine for now for me at least. Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment