Skip to content
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

Refreshed Token does not contain requested scopes #786

Closed
6 tasks done
objectiveSee opened this issue Oct 30, 2023 · 8 comments
Closed
6 tasks done

Refreshed Token does not contain requested scopes #786

objectiveSee opened this issue Oct 30, 2023 · 8 comments
Labels
bug This points to a verified bug in the code iOS Used to denote issues raised for iOS Platform

Comments

@objectiveSee
Copy link

Checklist

Description

Our app is using a custom scope OURAPP_ID_SCOPE inside the Auth0 token. Specifically this is used to get the userId. The token correctly contains a value for the OURAPP_ID_SCOPE property when we do an initial login. However, when we do a refresh token we notice that the userId property is missing. We would like to be able to use the

Here is some example code. See [The Problem] in the code. It seems that the user property from the Auth0 hook does not update contain the requested scope after a token refresh.

Any help is much appreciated! Please let me know if I can test anything specific to help you debug. 🙏

/**
 * Auth0 authorization parameters
 */
const options = {};
const BASE_SCOPE = 'openid profile email';
const OURAPP_ID_SCOPE = 'https://dev.ourapp.team/userId';
const REFRESH_TOKEN_SCOPE = 'offline_access';
const scope = [BASE_SCOPE, OURAPP_ID_SCOPE, REFRESH_TOKEN_SCOPE].join(' ');

const parameters = {
  audience: 'https://api.dev.ourapp.team/',
  scope: scope
};

const AuthContextProvider = ({ children }: Props) => {
  const { authorize, user, getCredentials, hasValidCredentials } = useAuth0();

  // Login function
  const login = useCallback(async () => {
    try {
      const { accessToken, expiresAt } = await authorize(parameters, options);
      if (accessToken && expiresAt) {
        setApiAccessToken(accessToken);
      }
    } catch (error) {
      console.log(`Auth0 Error on login:`, error);
    }
  }
  , [authorize]);

  // On app launch
  useEffect(() => {
    const loadApiAccessToken = async () => {
      try {
        const isLoggedIn = await hasValidCredentials(0);
        if ( !isLoggedIn ) {
          return
        }

        /* 
          [The Problem]
          We've tried `undefined` and `scope` for the first parameter of `getCredentials`.
          `scope` is the same variable that is used in the `authorize` call (which expectedly
          returns us our custom OURAPP_ID_SCOPE url that can be used to access the `userId`).
          However, when used in the `getCredentials` call, we don't get our custom OURAPP_ID_SCOPE
          url and so cannot access our `userId`.
        */
        const { accessToken, expiresAt } = await getCredentials(scope, undefined, undefined, true)
        if (accessToken && expiresAt) {
          setApiAccessToken(accessToken);
        }
      } catch (error) {
        console.log('Auth0: Error loading accessToken', error)
      }
    }
    if ( !apiAccessToken ) {
      loadApiAccessToken()
    }
  }, [apiAccessToken, getCredentials, hasValidCredentials])

  const userData = useMemo(() => {
    if ( !user ) {
      return undefined
    }

    const { name, email, picture } = user;
    const userId = user[OURAPP_ID_SCOPE];

    // Manually check properties that we assume are required
    // TODO: Verify w/ server that these properties are correct and required vs optional
    if ( !name || !email || !userId ) {
      console.log(`Auth0: Error: missing required user data`, user)
      return undefined
    }
    return {
      name,
      email,
      picture,
      id: userId
    }
  }, [user]);

  return { ..., userData, ... }

}

Reproduction

  1. Login. See user[OURAPP_ID_SCOPE] is defined
  2. Close app
  3. Re-launch app. Token refresh kicks off.
  4. After token refresh, user[OURAPP_ID_SCOPE] is undefined

Additional context

No response

react-native-auth0 version

3.0.0

React Native version

0.72.4

Expo version

~49.0.7

Platform

iOS

Platform version(s)

iOS Simulator 16.4

@objectiveSee objectiveSee added the bug This points to a verified bug in the code label Oct 30, 2023
@poovamraj
Copy link
Contributor

@objectiveSee Can you confirm 3 things?

  • Is the userId set as a custom claim in the ID Token?
  • Is it set as a part of auth0 actions?
  • Can you verify that the response received in the ID token has this value?

@poovamraj poovamraj assigned Widcket and unassigned Widcket Nov 6, 2023
@poovamraj poovamraj added the iOS Used to denote issues raised for iOS Platform label Nov 6, 2023
@objectiveSee
Copy link
Author

objectiveSee commented Nov 6, 2023

Hey @poovamraj and @Widcket, Here's answers to those questions:

Is the userId set as a custom claim in the ID Token?
yes. The OURAPP_ID_SCOPE custom claim is how we are retrieving the userId

Is it set as a part of auth0 actions?
It is part of a custom post login action. Here's the code segment:

if (event.authorization) {
        // Set claims
        api.idToken.setCustomClaim(`${namespace}/OURAPP_ID_SCOPE`, userId);
        api.idToken.setCustomClaim(`${namespace}/roles`, event.authorization.roles);
        api.accessToken.setCustomClaim(`${namespace}/OURAPP_ID_SCOPE`, userId);
        api.accessToken.setCustomClaim(`${namespace}/roles`, event.authorization.roles);
    }

Can you verify that the response received in the ID token has this value?
The response contains the claim on initial login, but not when we call getCredentials on subsequent app launches.

@poovamraj
Copy link
Contributor

@objectiveSee So you are saying the response received from the auth0 server doesn't have the required value? Then it has to be checked on the action implementation. If the response has the required value and it is only the SDK that is not getting it, then it has to be checked on the SDK.

So are you sure the claim is not present in the server response itself? In that case we can forward this internally to the correct team. You can also raise a request in our Community. On the other hand, if you are a paid customer, you can reach out to our Developer Support team who can expedite this for you.

I am not sure whether this is because the event.authorization object is undefined if the auth0 session already exists on the browser.

@objectiveSee
Copy link
Author

Sorry for the confusion @poovamraj. Let me clarify. What we are seeing is that the user property from the Auth0 hook is behaving different depending on whether or not the user logged in during the current app session, versus a previous one (eg. existing auth)

In the following example, the value of user will not contain the custom scope properties if we re-launch the app. Our custom scope is https://dev.fleet.ourapp.team/userId.

NOTE: user data and our team URLs are anonymized (using ChatGPT)

const options = {};
const BASE_SCOPE = 'openid profile email';
const USER_ID_SCOPE = 'https://dev.fleet.ourapp.team/userId';
const REFRESH_TOKEN_SCOPE = 'offline_access';
const scope = [BASE_SCOPE, USER_ID_SCOPE, REFRESH_TOKEN_SCOPE].join(' ');

const parameters = {
  audience: 'https://api.dev.fleet.ourapp.team/',
  scope: scope
};

const AuthContextProvider = ({ children }: AuthContextProviderProps) => {
  const { authorize, isLoading, user, error, clearSession, getCredentials, hasValidCredentials } = useAuth0();
  const [apiAccessToken, setApiAccessToken] = useState<string | undefined>();
  if ( user ) {
    console.log(`⭐️ user: ${JSON.stringify(user)}`);
  }

User value if this session started with login then https://dev.fleet.ourapp.team/userId is defined

{
  "https://dev.fleet.ourapp.team/userId": "random123456",
  "https://dev.fleet.ourapp.team/roles": [],
  "givenName": "UserFirstName",
  "familyName": "UserLastName",
  "nickname": "usernickname",
  "name": "UserFirstName UserLastName",
  "picture": "https://example.com/anon-profile-pic.png",
  "locale": "en",
  "updatedAt": "2023-11-06T19:17:34.389Z",
  "email": "useremail@ourapp.team",
  "emailVerified": true,
  "sub": "anon-oauth2|randomizedUserId"
}

User value on subsequent app launches. Notice that the custom scope variable is missing.

{
  "givenName": "UserFirstName",
  "familyName": "UserLastName",
  "nickname": "usernickname",
  "name": "UserFirstName UserLastName",
  "picture": "https://example.com/anon-profile-pic.png",
  "locale": "en",
  "updatedAt": "2023-11-06T19:17:34.389Z",
  "email": "useremail@ourapp.team",
  "emailVerified": true,
  "sub": "anon-oauth2|randomizedUserId"
}

@poovamraj
Copy link
Contributor

@objectiveSee from our understanding this is because of event check here which will not be triggered for subsequent logins

if (event.authorization)

And doesn't look like an SDK issue. Can you remove this check and verify?

@objectiveSee
Copy link
Author

objectiveSee commented Nov 8, 2023

Thank you for the help @poovamraj. Unfortunately this change didn't fix things. I posted an issue on the Auth0 community. We are a paid account so I will try to get this escalated. In the meantime we may just cache the custom claim info so as a placeholder solution.

We have a paid account, but I am not sure how to escalate an issue.

https://community.auth0.com/t/missing-custom-claim-in-token/120485

@poovamraj
Copy link
Contributor

@objectiveSee you can try as suggested here - https://auth0.com/docs/troubleshoot/customer-support/open-and-manage-support-tickets.

I am assuming this is not an issue on the SDK but in the action. We will keep a look out for the support ticket if it reaches as an issue in the SDK. In which case we will reopen this ticket as well and provide updates on the solution so that the community is in the loop as well. Hope this works and we will close this issue now.

You can still comment here if you need any help and we can reopen this issue if required.

@objectiveSee
Copy link
Author

This issue was resolved. See the Auth0 ticket linked above for resolution. Thanks to everyone @ Auth0 :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug This points to a verified bug in the code iOS Used to denote issues raised for iOS Platform
Projects
None yet
Development

No branches or pull requests

3 participants