|
17 | 17 | 15. [How do I know if my tokens are using DPoP?](#15-how-do-i-know-if-my-tokens-are-using-dpop) |
18 | 18 | 16. [What happens if I disable DPoP after enabling it?](#16-what-happens-if-i-disable-dpop-after-enabling-it) |
19 | 19 | 17. [Why does the app hang or freeze during Social Login (Google, Facebook, etc.)?](#17-why-does-the-app-hang-or-freeze-during-social-login-google-facebook-etc) |
| 20 | +18. [How do I refresh the user profile (e.g. `emailVerified`) after it changes on the server?](#18-how-do-i-refresh-the-user-profile-eg-emailverified-after-it-changes-on-the-server) |
20 | 21 |
|
21 | 22 | ## 1. How can I have separate Auth0 domains for each environment on Android? |
22 | 23 |
|
@@ -937,3 +938,87 @@ plutil -p ios/YourApp/Info.plist | grep -A 5 "CFBundleURLSchemes" |
937 | 938 | ``` |
938 | 939 |
|
939 | 940 | > **Note**: The SDK automatically lowercases your package/bundle identifier. If it's `com.example.MyApp`, the callback URL uses `com.example.myapp`. |
| 941 | + |
| 942 | +## 18. How do I refresh the user profile (e.g. `emailVerified`) after it changes on the server? |
| 943 | + |
| 944 | +A common scenario is email verification: a user signs up, receives a verification email, clicks the link, and returns to the app. However, the `user` object from `useAuth0()` still shows `emailVerified: false` because the user state is derived from the ID token claims, which are cached locally. |
| 945 | + |
| 946 | +To get the updated user profile, you need to force-refresh the credentials so the SDK fetches a new ID token with the latest claims from Auth0. |
| 947 | + |
| 948 | +### Prerequisites |
| 949 | + |
| 950 | +1. **Include `offline_access` in the scope during the initial login.** This is required because `forceRefresh` uses the refresh token to obtain new credentials. Without it, calling `getCredentials` with `forceRefresh: true` will fail with a `NO_REFRESH_TOKEN` error. |
| 951 | + |
| 952 | +2. **Use `forceRefresh: true` when calling `getCredentials`.** This forces the SDK to call the `/oauth/token` endpoint and fetch a new ID token with up-to-date claims. |
| 953 | + |
| 954 | +### Step-by-Step Example |
| 955 | + |
| 956 | +**Step 1: Log in with `offline_access` scope** |
| 957 | + |
| 958 | +```tsx |
| 959 | +import { useAuth0 } from 'react-native-auth0'; |
| 960 | +
|
| 961 | +function LoginScreen() { |
| 962 | + const { authorize } = useAuth0(); |
| 963 | +
|
| 964 | + const handleLogin = async () => { |
| 965 | + await authorize({ |
| 966 | + scope: 'openid profile email offline_access', // offline_access is required |
| 967 | + }); |
| 968 | + }; |
| 969 | +
|
| 970 | + // ... |
| 971 | +} |
| 972 | +``` |
| 973 | + |
| 974 | +**Step 2: After the user verifies their email (or any server-side profile change), force-refresh credentials** |
| 975 | + |
| 976 | +```tsx |
| 977 | +import { useAuth0 } from 'react-native-auth0'; |
| 978 | +
|
| 979 | +function VerifyEmailScreen() { |
| 980 | + const { user, getCredentials } = useAuth0(); |
| 981 | +
|
| 982 | + const refreshUserProfile = async () => { |
| 983 | + try { |
| 984 | + await getCredentials( |
| 985 | + 'openid profile email offline_access', |
| 986 | + undefined, // minTtl |
| 987 | + undefined, // parameters |
| 988 | + true // forceRefresh — forces a new token request |
| 989 | + ); |
| 990 | + // After this call, the `user` object from useAuth0() will be updated |
| 991 | + // with the latest claims (e.g., emailVerified: true) |
| 992 | + } catch (error) { |
| 993 | + console.error('Failed to refresh credentials:', error); |
| 994 | + } |
| 995 | + }; |
| 996 | +
|
| 997 | + if (user?.emailVerified) { |
| 998 | + return <Text>Email verified! You're all set.</Text>; |
| 999 | + } |
| 1000 | +
|
| 1001 | + return ( |
| 1002 | + <View> |
| 1003 | + <Text>Please verify your email, then tap the button below.</Text> |
| 1004 | + <Button title="I've verified my email" onPress={refreshUserProfile} /> |
| 1005 | + </View> |
| 1006 | + ); |
| 1007 | +} |
| 1008 | +``` |
| 1009 | + |
| 1010 | +### How It Works |
| 1011 | + |
| 1012 | +1. `getCredentials` with `forceRefresh: true` uses the stored refresh token to call the Auth0 `/oauth/token` endpoint. |
| 1013 | +2. Auth0 returns a new ID token whose claims reflect the current server-side user profile. |
| 1014 | +3. The SDK parses the new ID token and updates the `user` object in the `Auth0Provider` context. |
| 1015 | +4. Any component consuming `useAuth0()` will re-render with the updated user data. |
| 1016 | + |
| 1017 | +### Common Errors |
| 1018 | + |
| 1019 | +| Error | Cause | Fix | |
| 1020 | +| --------------------------------------- | ------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------- | |
| 1021 | +| `NO_REFRESH_TOKEN` | `offline_access` was not included in the `authorize()` scope | Add `offline_access` to the scope in the **initial** `authorize()` call. The user may need to log out and log in again. | |
| 1022 | +| `getCredentials` promise never resolves | Missing refresh token or network issue | Ensure `offline_access` is included during login, and check network connectivity. | |
| 1023 | + |
| 1024 | +> **Note**: This behavior differs from the web SDK (`@auth0/auth0-spa-js`), where token refresh is handled automatically via silent authentication using iframes. On native platforms (iOS/Android), a refresh token is explicitly required. |
0 commit comments