Skip to content

Commit ebcaade

Browse files
committed
fix: address public API audit review feedback
Restore src/exports/*.ts as thin re-exports of src/index.ts (rather than internal modules) so `yarn docs` builds again and TypeDoc's Classes/Enums/ Hooks/Interface grouping survives the barrel deletion; cover it with a freeze test so it can't silently drift from the frozen surface again. Read the RFC 7807 `status` field before the nonstandard `statusCode` in MyAccountError, so a spec-compliant problem document is classified correctly even when the underlying AuthError.status wasn't populated. Strengthen the "Auth0 is a named alias for default" test to compare resolved TypeScript symbols instead of only checking both names exist. Fix the Custom Token Exchange example in EXAMPLES.md to use the documented unsupported_token_type/unauthorized_client codes, correct the contradictory error-taxonomy guidance in README.md (code-vs-type switch scope, a false exhaustiveness claim), and fix the truncated typeUri example in both docs. Document the MyAccountError.type breaking change and the four removed exports in MIGRATION_GUIDE.md, and correct its stale claim that the newly-exported client interfaces were never part of the entry point.
1 parent 4a2cb30 commit ebcaade

13 files changed

Lines changed: 319 additions & 169 deletions

File tree

EXAMPLES.md

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1013,10 +1013,13 @@ function TokenExchangeScreen() {
10131013
case 'invalid_grant':
10141014
Alert.alert('Error', 'The external token was rejected or expired');
10151015
break;
1016-
case 'unsupported_grant_type':
1016+
case 'unsupported_token_type':
1017+
Alert.alert('Error', 'The external token type is not supported');
1018+
break;
1019+
case 'unauthorized_client':
10171020
Alert.alert(
10181021
'Error',
1019-
'Custom Token Exchange is not enabled for this tenant'
1022+
'Custom Token Exchange is not enabled for this client'
10201023
);
10211024
break;
10221025
case 'access_denied':
@@ -1851,7 +1854,7 @@ error handling matches every other error class in the SDK, and preserves the ori
18511854
catch (e) {
18521855
if (e instanceof MyAccountError) {
18531856
console.log(e.type); // "UNAUTHORIZED" — normalized, switch on this
1854-
console.log(e.typeUri); // "https://auth0.com/api-errors/A0E-401" — raw, log this
1857+
console.log(e.typeUri); // "https://auth0.com/api-errors/A0E-401-0001" — raw, log this
18551858
console.log(e.statusCode); // 401
18561859
}
18571860
}

MIGRATION_GUIDE.md

Lines changed: 23 additions & 1 deletion
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 [Public API surface freeze](#11-public-api-surface-freeze--my-account-error-normalization) below); 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

README.md

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -670,19 +670,24 @@ The options for configuring the display of local authentication prompt, authenti
670670
671671
### Error taxonomy
672672

673-
Every error the SDK throws extends `AuthError` and carries a **normalized, platform-agnostic**
674-
`type`. Switch on `type` — never on `code` — and your error handling behaves identically on iOS,
675-
Android, and web.
676-
677-
| Property | Use it for |
678-
| --------- | ---------------------------------------------------------------------------------------------------------- |
679-
| `type` | **Control flow.** A normalized code, stable across platforms. Compare against the `…ErrorCodes` constants. |
680-
| `code` | **Diagnostics.** The raw code from the underlying platform SDK or wire response. Varies by platform. |
681-
| `message` | Human-readable description. Not stable — do not parse it. |
682-
| `status` | HTTP status, when the failure came from an HTTP response (`0` otherwise). |
683-
684-
Each error class ships a companion constants object and a matching TypeScript union, so a `switch`
685-
on `type` is exhaustively checked at compile time:
673+
Every error the SDK throws extends `AuthError`. The six normalized subclasses below carry a
674+
**normalized, platform-agnostic** `type` — switch on `type`, not `code`, for these and your error
675+
handling behaves identically on iOS, Android, and web. Flows that throw a plain `AuthError`
676+
instead — for example [Custom Token Exchange](EXAMPLES.md#custom-token-exchange-rfc-8693), which surfaces
677+
the raw OAuth error from the token endpoint — don't get a normalized `type`; there, `code` is the
678+
correct (and only) thing to switch on.
679+
680+
| Property | Use it for |
681+
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
682+
| `type` | **Control flow** for the six normalized subclasses. A normalized code, stable across platforms. Compare against the `…ErrorCodes` constants. |
683+
| `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`. |
684+
| `message` | Human-readable description. Not stable — do not parse it. |
685+
| `status` | HTTP status, when the failure came from an HTTP response (`0` otherwise). |
686+
687+
Each of the six normalized classes ships a companion constants object and a matching TypeScript
688+
union. Handle every value explicitly (no `default` branch) and TypeScript enforces exhaustiveness
689+
at compile time — a `switch` missing a case fails to compile. The example below adds a `default`
690+
fallback for brevity, so it does not get that compile-time guarantee:
686691

687692
| Error class | Constants | Type union | Thrown by |
688693
| ------------------------- | ------------------------------ | ---------------------------------- | ----------------------------------------------- |
@@ -719,7 +724,7 @@ class — it keeps `switch` statements exhaustive and rejects codes that cannot
719724
720725
`MyAccountError` is the one class with an extra property: the My Account API reports failures as
721726
[RFC 7807](https://datatracker.ietf.org/doc/html/rfc7807) type URIs, so `type` holds the normalized
722-
code while `typeUri` preserves the original URI (e.g. `https://auth0.com/api-errors/A0E-401`) for
727+
code while `typeUri` preserves the original URI (e.g. `https://auth0.com/api-errors/A0E-401-0001`) for
723728
logging and support tickets.
724729

725730
### Credentials Manager errors
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)