Skip to content

Commit 79b3b67

Browse files
Merge branch 'v6-development' into feat/ios-privacy-manifest
2 parents 86d75d4 + 0305565 commit 79b3b67

33 files changed

Lines changed: 1166 additions & 85 deletions

EXAMPLES.md

Lines changed: 38 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -985,11 +985,7 @@ Custom Token Exchange allows you to exchange external identity provider tokens f
985985
```typescript
986986
import React from 'react';
987987
import { Button, Alert } from 'react-native';
988-
import {
989-
useAuth0,
990-
AuthenticationException,
991-
AuthenticationErrorCodes,
992-
} from 'react-native-auth0';
988+
import { useAuth0, AuthError } from 'react-native-auth0';
993989

994990
function TokenExchangeScreen() {
995991
const { customTokenExchange, user, error } = useAuth0();
@@ -1006,25 +1002,28 @@ function TokenExchangeScreen() {
10061002

10071003
Alert.alert('Success', `Logged in as ${user?.name}`);
10081004
} catch (e) {
1009-
if (e instanceof AuthenticationException) {
1010-
switch (e.type) {
1011-
case AuthenticationErrorCodes.INVALID_SUBJECT_TOKEN:
1012-
Alert.alert('Error', 'The external token is invalid or expired');
1005+
if (e instanceof AuthError) {
1006+
// Custom Token Exchange surfaces the OAuth 2.0 error from the token
1007+
// endpoint on `code`. See the RFC 8693 error responses and your Action's
1008+
// own failure reasons.
1009+
switch (e.code) {
1010+
case 'invalid_request':
1011+
Alert.alert('Error', 'The external token or token type is invalid');
1012+
break;
1013+
case 'invalid_grant':
1014+
Alert.alert('Error', 'The external token was rejected or expired');
10131015
break;
1014-
case AuthenticationErrorCodes.UNSUPPORTED_TOKEN_TYPE:
1015-
Alert.alert('Error', 'The token type is not supported');
1016+
case 'unsupported_token_type':
1017+
Alert.alert('Error', 'The external token type is not supported');
10161018
break;
1017-
case AuthenticationErrorCodes.TOKEN_EXCHANGE_NOT_CONFIGURED:
1019+
case 'unauthorized_client':
10181020
Alert.alert(
10191021
'Error',
1020-
'Custom Token Exchange is not configured for this tenant'
1022+
'Custom Token Exchange is not enabled for this client'
10211023
);
10221024
break;
1023-
case AuthenticationErrorCodes.TOKEN_VALIDATION_FAILED:
1024-
Alert.alert('Error', 'Token validation failed in Auth0 Action');
1025-
break;
1026-
case AuthenticationErrorCodes.NETWORK_ERROR:
1027-
Alert.alert('Error', 'Network error. Please check your connection.');
1025+
case 'access_denied':
1026+
Alert.alert('Error', 'Token validation failed in the Auth0 Action');
10281027
break;
10291028
default:
10301029
Alert.alert('Error', e.message);
@@ -1042,10 +1041,7 @@ function TokenExchangeScreen() {
10421041
### Using Custom Token Exchange with Auth0 Class
10431042
10441043
```typescript
1045-
import Auth0, {
1046-
AuthenticationException,
1047-
AuthenticationErrorCodes,
1048-
} from 'react-native-auth0';
1044+
import Auth0, { AuthError } from 'react-native-auth0';
10491045
10501046
const auth0 = new Auth0({
10511047
domain: 'YOUR_AUTH0_DOMAIN',
@@ -1064,14 +1060,14 @@ async function exchangeExternalToken(externalToken: string) {
10641060
console.log('Exchange successful:', credentials);
10651061
return credentials;
10661062
} catch (error) {
1067-
if (error instanceof AuthenticationException) {
1063+
if (error instanceof AuthError) {
10681064
// Access the underlying error details
1069-
console.error('Error type:', error.type);
1065+
console.error('Error code:', error.code);
10701066
console.error('Error message:', error.message);
1071-
console.error('Underlying error code:', error.underlyingError.code);
1067+
console.error('HTTP status:', error.status);
10721068
1073-
// Handle specific error types
1074-
if (error.type === AuthenticationErrorCodes.INVALID_SUBJECT_TOKEN) {
1069+
// Handle specific error codes
1070+
if (error.code === 'invalid_grant') {
10751071
// Token is invalid or expired - prompt user to re-authenticate
10761072
throw new Error('Please authenticate again with the external provider');
10771073
}
@@ -1849,6 +1845,21 @@ try {
18491845
}
18501846
```
18511847
1848+
The My Account API reports failures as [RFC 7807](https://datatracker.ietf.org/doc/html/rfc7807)
1849+
type URIs. `MyAccountError` normalizes those to a `MyAccountErrorCodes` value on `type` so your
1850+
error handling matches every other error class in the SDK, and preserves the original URI on
1851+
`typeUri` for logging or support tickets:
1852+
1853+
```typescript
1854+
catch (e) {
1855+
if (e instanceof MyAccountError) {
1856+
console.log(e.type); // "UNAUTHORIZED" — normalized, switch on this
1857+
console.log(e.typeUri); // "https://auth0.com/api-errors/A0E-401-0001" — raw, log this
1858+
console.log(e.statusCode); // 401
1859+
}
1860+
}
1861+
```
1862+
18521863
### Platform Support
18531864
18541865
| Platform | Support | Notes |

MIGRATION_GUIDE.md

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -248,7 +248,29 @@ Only one of these was exported to consumers:
248248
249249
**✅ Action Required:** rename the import if you annotated anything with `IMfaClient` — typically a variable holding `auth0.mfa` or the `mfa` object from `useAuth0()`. This is a type-only change; runtime behaviour is identical.
250250
251-
The rest (`AuthenticationProvider`, `CredentialsManager`, `MyAccountClient`, `PasswordlessClient`, `WebAuthProvider`, `NativeBridge`) were never exported from the package entry point, so nothing to do there.
251+
`AuthenticationProvider`, `CredentialsManager`, `MyAccountClient`, `PasswordlessClient`, and `WebAuthProvider` are now exported under their plain names too _(see [§11](#11-public-api-surface-freeze--my-account-error-normalization-))_; only `NativeBridge` stays internal-only.
252+
253+
### 11. Public API surface freeze & My Account error normalization ✅
254+
255+
The public surface was audited before v6 GA: previously-unreachable types were exported, dead internal types were un-exported, and `MyAccountError` was brought in line with the rest of the error taxonomy.
256+
257+
#### `MyAccountError.type` is now a normalized code
258+
259+
`MyAccountError.type` used to be the raw [RFC 7807](https://datatracker.ietf.org/doc/html/rfc7807) type URI reported by the My Account API (e.g. `https://auth0.com/api-errors/A0E-401-0001`). It is now a normalized `MyAccountErrorCodes` value, consistent with every other error class in the SDK. The original URI is preserved on a new `typeUri` property.
260+
261+
**⚠️ Action Required:** if you compared `MyAccountError.type` against a raw URI string, switch to comparing against `MyAccountErrorCodes` and read `typeUri` for the raw value.
262+
263+
```diff
264+
- if (error.type === 'https://auth0.com/api-errors/A0E-401-0001') { ... }
265+
+ if (error.type === MyAccountErrorCodes.UNAUTHORIZED) { ... }
266+
+ console.log(error.typeUri); // "https://auth0.com/api-errors/A0E-401-0001" — raw, log this
267+
```
268+
269+
#### Four internal types are no longer exported
270+
271+
`NativeAuth0Options`, `WebAuth0Options`, `NativeCredentialsResponse`, and `SSOCredentialsResponse` were internal adapter-construction/wire shapes that were reachable from `react-native-auth0` by accident. They are not part of the supported API and have been removed from the package's exports.
272+
273+
**✅ Action Required:** if you imported any of these four types directly, inline the shape you need or open an issue describing your use case — none of them were meant to be public.
252274
253275
### Recommended Reading
254276
@@ -365,7 +387,7 @@ With the introduction of **React Native Web support**, some methods are only ava
365387
366388
On React Native Web, the `authorize()` method now triggers a **full-page redirect** to Auth0. As a result, the promise returned by `authorize()` will **not resolve** in the browser. Your application must be structured to handle the user state upon reloading after the redirect.
367389
368-
**✅ Action Required:** Review the new **[FAQ entry](#faq-authorize-web)** for guidance on how to correctly handle the post-login flow on the web. The `Auth0Provider` and `useAuth0` hook are designed to manage this flow automatically.
390+
**✅ Action Required:** Review the new **[FAQ entry](FAQ.md#9-why-doesnt-await-authorize-work-on-the-web-how-do-i-handle-login)** for guidance on how to correctly handle the post-login flow on the web. The `Auth0Provider` and `useAuth0` hook are designed to manage this flow automatically.
369391
370392
### Change #5: Hook Methods Now Throw Error
371393

README.md

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -670,6 +670,65 @@ The options for configuring the display of local authentication prompt, authenti
670670

671671
> :warning: You need a real device to test Local Authentication for iOS. Local Authentication is not available in simulators.
672672
673+
### Error taxonomy
674+
675+
Every error the SDK throws extends `AuthError`. The six normalized subclasses below carry a
676+
**normalized, platform-agnostic** `type` — switch on `type`, not `code`, for these and your error
677+
handling behaves identically on iOS, Android, and web. Flows that throw a plain `AuthError`
678+
instead — for example [Custom Token Exchange](EXAMPLES.md#custom-token-exchange-rfc-8693), which surfaces
679+
the raw OAuth error from the token endpoint — don't get a normalized `type`; there, `code` is the
680+
correct (and only) thing to switch on.
681+
682+
| Property | Use it for |
683+
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
684+
| `type` | **Control flow** for the six normalized subclasses. A normalized code, stable across platforms. Compare against the `…ErrorCodes` constants. |
685+
| `code` | **Diagnostics** for the normalized subclasses (raw code from the underlying platform SDK or wire response, varies by platform); **control flow** for plain `AuthError` flows that have no normalized `type`. |
686+
| `message` | Human-readable description. Not stable — do not parse it. |
687+
| `status` | HTTP status, when the failure came from an HTTP response (`0` otherwise). |
688+
689+
Each of the six normalized classes ships a companion constants object and a matching TypeScript
690+
union. Handle every value explicitly (no `default` branch) and TypeScript enforces exhaustiveness
691+
at compile time — a `switch` missing a case fails to compile. The example below adds a `default`
692+
fallback for brevity, so it does not get that compile-time guarantee:
693+
694+
| Error class | Constants | Type union | Thrown by |
695+
| ------------------------- | ------------------------------ | ---------------------------------- | ----------------------------------------------- |
696+
| `WebAuthError` | `WebAuthErrorCodes` | `WebAuthErrorCode` | `webAuth.authorize()`, `webAuth.clearSession()` |
697+
| `CredentialsManagerError` | `CredentialsManagerErrorCodes` | `CredentialsManagerErrorCode` | `credentialsManager.*` |
698+
| `MfaError` | `MfaErrorCodes` | `MfaErrorCode` | `mfa.*` |
699+
| `PasskeyError` | `PasskeyErrorCodes` | `PasskeyErrorCode` | passkey signup/login and passkey enrollment |
700+
| `MyAccountError` | `MyAccountErrorCodes` | `MyAccountErrorCode` | `myAccount.*` |
701+
| `DPoPError` | `DPoPErrorCodes` | `DPoPErrorCode` | `getDPoPHeaders()` and DPoP key handling |
702+
| `TimeoutError` || `type` is always `'TIMEOUT_ERROR'` | HTTP requests exceeding `timeout` |
703+
704+
```typescript
705+
import { WebAuthError, WebAuthErrorCodes } from 'react-native-auth0';
706+
import type { WebAuthErrorCode } from 'react-native-auth0';
707+
708+
function describe(type: WebAuthErrorCode): string {
709+
switch (type) {
710+
case WebAuthErrorCodes.USER_CANCELLED:
711+
return 'Cancelled';
712+
case WebAuthErrorCodes.NETWORK_ERROR:
713+
return 'Offline';
714+
default:
715+
return 'Login failed';
716+
}
717+
}
718+
```
719+
720+
`Auth0ErrorCode` is the union of all of the above. Prefer the specific union when handling one error
721+
class — it keeps `switch` statements exhaustive and rejects codes that cannot occur there. Reach for
722+
`Auth0ErrorCode` only in generic code such as logging or telemetry.
723+
724+
> **Stability.** These constants, their unions, and the `type` values they contain are the public
725+
> error contract. Values will not be removed or renamed outside a major version.
726+
727+
`MyAccountError` is the one class with an extra property: the My Account API reports failures as
728+
[RFC 7807](https://datatracker.ietf.org/doc/html/rfc7807) type URIs, so `type` holds the normalized
729+
code while `typeUri` preserves the original URI (e.g. `https://auth0.com/api-errors/A0E-401-0001`) for
730+
logging and support tickets.
731+
673732
### Credentials Manager errors
674733

675734
The Credentials Manager will only throw `CredentialsManagerError` exceptions. You can find more information in the details property of the exception.

src/Auth0.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import type { MfaClient } from './core/interfaces/MfaClient';
33
import { Auth0ClientFactory } from './factory/Auth0ClientFactory';
44
import type {
55
Auth0Options,
6-
DPoPHeadersParams,
6+
DPoPHeadersParameters,
77
CustomTokenExchangeParameters,
88
PasskeySignupChallengeParameters,
99
PasskeyLoginChallengeParameters,
@@ -122,7 +122,7 @@ class Auth0 {
122122
* }
123123
* ```
124124
*/
125-
getDPoPHeaders(params: DPoPHeadersParams) {
125+
getDPoPHeaders(params: DPoPHeadersParameters) {
126126
return this.client.getDPoPHeaders(params);
127127
}
128128

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
/**
2+
* The frozen public API surface of `src/index.ts`.
3+
*
4+
* This list is the stable public contract for v6. Adding an entry is a minor
5+
* change; **removing or renaming an entry is a breaking change** and must be
6+
* treated as such (major version, deprecation cycle, changelog entry).
7+
*
8+
* If a test fails against this list, do not "fix" it by regenerating the
9+
* list. Confirm the change to the surface is intentional and versioned
10+
* appropriately first.
11+
*/
12+
export const FROZEN_PUBLIC_API = [
13+
'ApiCredentials',
14+
'Auth0',
15+
'Auth0Client',
16+
'Auth0ContextInterface',
17+
'Auth0ErrorCode',
18+
'Auth0Options',
19+
'Auth0Provider',
20+
'AuthError',
21+
'AuthState',
22+
'AuthenticationMethod',
23+
'AuthenticationMethodType',
24+
'AuthenticationMethodTypes',
25+
'AuthenticationProvider',
26+
'AuthorizeUrlParameters',
27+
'BiometricPolicy',
28+
'ClearSessionParameters',
29+
'ConfirmOTPEnrollmentParameters',
30+
'ConfirmPushNotificationEnrollmentParameters',
31+
'ConfirmRecoveryCodeEnrollmentParameters',
32+
'CreateUserParameters',
33+
'Credentials',
34+
'CredentialsManager',
35+
'CredentialsManagerError',
36+
'CredentialsManagerErrorCode',
37+
'CredentialsManagerErrorCodes',
38+
'CustomTokenExchangeParameters',
39+
'DPoPError',
40+
'DPoPErrorCode',
41+
'DPoPErrorCodes',
42+
'DPoPHeadersParameters',
43+
'DPoPHeadersParams',
44+
'DeleteAuthenticationMethodByIdParameters',
45+
'DeliveryMethod',
46+
'EnrollEmailParameters',
47+
'EnrollPasskeyParameters',
48+
'EnrollPhoneParameters',
49+
'EnrollPushNotificationParameters',
50+
'EnrollRecoveryCodeParameters',
51+
'EnrollTOTPParameters',
52+
'EnrollmentChallenge',
53+
'ExchangeNativeSocialParameters',
54+
'ExchangeParameters',
55+
'Factor',
56+
'GetAuthenticationMethodByIdParameters',
57+
'GetAuthenticationMethodsParameters',
58+
'GetFactorsParameters',
59+
'GetTokenByPasskeyParameters',
60+
'LocalAuthenticationLevel',
61+
'LocalAuthenticationOptions',
62+
'LocalAuthenticationStrategy',
63+
'LoginEmailParameters',
64+
'LoginSmsParameters',
65+
'LogoutUrlParameters',
66+
'MfaAuthenticator',
67+
'MfaChallengeResult',
68+
'MfaChallengeWithAuthenticatorParameters',
69+
'MfaClient',
70+
'MfaEnrollEmailParameters',
71+
'MfaEnrollOtpParameters',
72+
'MfaEnrollParameters',
73+
'MfaEnrollPushParameters',
74+
'MfaEnrollSmsParameters',
75+
'MfaEnrollVoiceParameters',
76+
'MfaEnrollmentChallenge',
77+
'MfaError',
78+
'MfaErrorCode',
79+
'MfaErrorCodes',
80+
'MfaFactor',
81+
'MfaFactorType',
82+
'MfaGetAuthenticatorsParameters',
83+
'MfaOobEnrollmentChallenge',
84+
'MfaPushEnrollmentChallenge',
85+
'MfaRecoveryCodeEnrollmentChallenge',
86+
'MfaRequiredErrorPayload',
87+
'MfaRequirements',
88+
'MfaTotpEnrollmentChallenge',
89+
'MfaVerifyOobParameters',
90+
'MfaVerifyOtpParameters',
91+
'MfaVerifyParameters',
92+
'MfaVerifyRecoveryCodeParameters',
93+
'MyAccountClient',
94+
'MyAccountError',
95+
'MyAccountErrorCode',
96+
'MyAccountErrorCodes',
97+
'NativeAuthorizeOptions',
98+
'NativeClearSessionOptions',
99+
'PasskeyAuthenticationMethod',
100+
'PasskeyChallengeResponse',
101+
'PasskeyEnrollmentChallengeParameters',
102+
'PasskeyEnrollmentChallengeResponse',
103+
'PasskeyError',
104+
'PasskeyErrorCode',
105+
'PasskeyErrorCodes',
106+
'PasskeyLoginChallengeParameters',
107+
'PasskeySignupChallengeParameters',
108+
'PasswordRealmParameters',
109+
'PasswordlessChallenge',
110+
'PasswordlessChallengeEmailParameters',
111+
'PasswordlessChallengePhoneParameters',
112+
'PasswordlessClient',
113+
'PasswordlessDeliveryMethod',
114+
'PasswordlessEmailParameters',
115+
'PasswordlessLoginOtpParameters',
116+
'PasswordlessSmsParameters',
117+
'PreferredAuthenticationMethods',
118+
'RecoveryCodeEnrollmentChallenge',
119+
'RefreshTokenParameters',
120+
'ResetPasswordParameters',
121+
'RevokeOptions',
122+
'SSOExchangeParameters',
123+
'SafariViewControllerPresentationStyle',
124+
'SessionTransferCredentials',
125+
'TOTPEnrollmentChallenge',
126+
'TimeoutError',
127+
'TokenType',
128+
'UpdateAuthenticationMethodByIdParameters',
129+
'User',
130+
'UserInfoParameters',
131+
'WebAuthError',
132+
'WebAuthErrorCode',
133+
'WebAuthErrorCodes',
134+
'WebAuthProvider',
135+
'WebAuthorizeOptions',
136+
'WebAuthorizeParameters',
137+
'WebClearSessionOptions',
138+
'default',
139+
'parseIdToken',
140+
'useAuth0',
141+
];

0 commit comments

Comments
 (0)