Skip to content

Commit af3e4d6

Browse files
feat: add Step-Up Authentication section and related examples to documentation (#1023)
## Summary Add step-up authentication support via popup for the refresh token flow. When `getAccessTokenSilently` encounters an `mfa_required` error, the SDK can now automatically open a Universal Login popup for the user to complete MFA, then return the token transparently — no custom MFA UI required. ## Changes - Export `PopupOpenError` and the `InteractiveErrorHandler` type from the public API, enabling consumers to handle popup errors and type the new configuration option - Add documentation and usage examples for step-up authentication via the `interactiveErrorHandler: "popup"` provider option, including setup, usage, and error handling ## Example ```jsx <Auth0Provider domain="YOUR_AUTH0_DOMAIN" clientId="YOUR_AUTH0_CLIENT_ID" authorizationParams={{ redirect_uri: window.location.origin, audience: 'https://api.example.com/', }} useRefreshTokens={true} interactiveErrorHandler="popup" > <MyApp /> </Auth0Provider> ``` Once configured, `getAccessTokenSilently` handles MFA challenges automatically: ```js const token = await getAccessTokenSilently({ authorizationParams: { audience: 'https://api.example.com/', scope: 'read:sensitive' }, }); ``` ## Testing - Verified `InteractiveErrorHandler` property behaviour via a step up flow
1 parent 92064d6 commit af3e4d6

File tree

4 files changed

+87
-6
lines changed

4 files changed

+87
-6
lines changed

EXAMPLES.md

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
- [Connect Accounts for using Token Vault](#connect-accounts-for-using-token-vault)
1414
- [Access SDK Configuration](#access-sdk-configuration)
1515
- [Multi-Factor Authentication (MFA)](#multi-factor-authentication-mfa)
16+
- [Step-Up Authentication](#step-up-authentication)
1617

1718
## Use with a Class Component
1819

@@ -990,3 +991,82 @@ try {
990991
}
991992
}
992993
```
994+
995+
## Step-Up Authentication
996+
997+
When a protected API requires MFA (step-up authentication), `getAccessTokenSilently` will receive an `mfa_required` error from Auth0. By configuring the `interactiveErrorHandler` option, the SDK can automatically handle this by opening a Universal Login popup for the user to complete MFA, then return the token transparently. No custom MFA UI is required — the entire flow is handled via Auth0's Universal Login.
998+
999+
If you need full control over the MFA experience (custom UI for enrollment, challenge, and verification), see the [Multi-Factor Authentication (MFA)](#multi-factor-authentication-mfa) section instead.
1000+
1001+
> [!WARNING]
1002+
> This feature only works with the refresh token flow (`useRefreshTokens={true}`) and only handles `mfa_required` errors. Other interactive errors are not intercepted.
1003+
1004+
### Setup
1005+
1006+
Configure `Auth0Provider` with `interactiveErrorHandler` set to `"popup"` and refresh tokens enabled:
1007+
1008+
```jsx
1009+
import { Auth0Provider } from '@auth0/auth0-react';
1010+
1011+
function App() {
1012+
return (
1013+
<Auth0Provider
1014+
domain="YOUR_AUTH0_DOMAIN"
1015+
clientId="YOUR_AUTH0_CLIENT_ID"
1016+
authorizationParams={{
1017+
redirect_uri: window.location.origin,
1018+
audience: 'https://api.example.com/',
1019+
}}
1020+
useRefreshTokens={true}
1021+
interactiveErrorHandler="popup"
1022+
>
1023+
<MyApp />
1024+
</Auth0Provider>
1025+
);
1026+
}
1027+
```
1028+
1029+
### Usage
1030+
1031+
With this configuration, `getAccessTokenSilently` automatically opens a popup when the token request triggers an `mfa_required` error. Once the user completes MFA in the popup, the token is returned as if the call succeeded normally:
1032+
1033+
```jsx
1034+
import React, { useEffect, useState } from 'react';
1035+
import { useAuth0 } from '@auth0/auth0-react';
1036+
1037+
const ProtectedResource = () => {
1038+
const { getAccessTokenSilently } = useAuth0();
1039+
const [data, setData] = useState(null);
1040+
1041+
useEffect(() => {
1042+
(async () => {
1043+
try {
1044+
// If MFA is required, a popup opens automatically.
1045+
// The token is returned after the user completes MFA.
1046+
const token = await getAccessTokenSilently({
1047+
authorizationParams: {
1048+
audience: 'https://api.example.com/',
1049+
scope: 'read:sensitive',
1050+
},
1051+
});
1052+
const response = await fetch('https://api.example.com/sensitive', {
1053+
headers: { Authorization: `Bearer ${token}` },
1054+
});
1055+
setData(await response.json());
1056+
} catch (e) {
1057+
console.error(e);
1058+
}
1059+
})();
1060+
}, [getAccessTokenSilently]);
1061+
1062+
if (!data) return <div>Loading...</div>;
1063+
return <div>{JSON.stringify(data)}</div>;
1064+
};
1065+
1066+
export default ProtectedResource;
1067+
```
1068+
1069+
### Error Handling
1070+
1071+
If the popup is blocked, cancelled, or times out, `getAccessTokenSilently` throws `PopupOpenError`, `PopupCancelledError`, or `PopupTimeoutError` respectively. These can be imported from `@auth0/auth0-react`.
1072+

package-lock.json

Lines changed: 4 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,6 @@
9595
"react-dom": "^16.11.0 || ^17 || ^18 || ~19.0.1 || ~19.1.2 || ^19.2.1"
9696
},
9797
"dependencies": {
98-
"@auth0/auth0-spa-js": "^2.15.0"
98+
"@auth0/auth0-spa-js": "^2.16.0"
9999
}
100100
}

src/index.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ export {
3535
MfaRequiredError,
3636
PopupCancelledError,
3737
PopupTimeoutError,
38+
PopupOpenError,
3839
AuthenticationError,
3940
MissingRefreshTokenError,
4041
GenericError,
@@ -44,6 +45,7 @@ export {
4445
ConnectAccountRedirectResult,
4546
ResponseType,
4647
ConnectError,
48+
type InteractiveErrorHandler,
4749
CustomTokenExchangeOptions,
4850
TokenEndpointResponse,
4951
ClientConfiguration,

0 commit comments

Comments
 (0)