react-native-oauth-essentials 1.0.12 → 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +384 -362
- package/android/src/main/java/com/oauthessentials/CredentialError.kt +4 -1
- package/android/src/main/java/com/oauthessentials/CredentialFactory.kt +24 -2
- package/android/src/main/java/com/oauthessentials/CustomTabsActivity.kt +14 -1
- package/android/src/main/java/com/oauthessentials/OauthEssentialsModule.kt +445 -187
- package/app.plugin.js +1 -0
- package/ios/AppleIdRetriever.swift +25 -26
- package/ios/CredentialError.swift +3 -0
- package/ios/CredentialFactory.swift +38 -20
- package/ios/CredentialsType.swift +1 -0
- package/ios/GoogleIdRetriever.swift +132 -56
- package/ios/HybridRetriever.swift +12 -18
- package/ios/OauthEssentials.h +0 -3
- package/ios/OauthEssentials.mm +45 -2
- package/ios/OauthEssentialsModule.swift +266 -57
- package/ios/PasskeyRetriever.swift +31 -49
- package/ios/PasswordRetriever.swift +10 -30
- package/ios/RCTPromiseSettler.swift +125 -0
- package/jest/index.js +149 -0
- package/lib/module/NativeOauthEssentials.js +10 -1
- package/lib/module/NativeOauthEssentials.js.map +1 -1
- package/lib/module/errors.js +38 -0
- package/lib/module/errors.js.map +1 -0
- package/lib/module/index.js +432 -58
- package/lib/module/index.js.map +1 -1
- package/lib/module/oauth.js +97 -0
- package/lib/module/oauth.js.map +1 -0
- package/lib/module/platform.js +108 -0
- package/lib/module/platform.js.map +1 -0
- package/lib/module/types.js +46 -1
- package/lib/module/types.js.map +1 -1
- package/lib/typescript/src/NativeOauthEssentials.d.ts +70 -16
- package/lib/typescript/src/NativeOauthEssentials.d.ts.map +1 -1
- package/lib/typescript/src/errors.d.ts +18 -0
- package/lib/typescript/src/errors.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +235 -40
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/oauth.d.ts +32 -0
- package/lib/typescript/src/oauth.d.ts.map +1 -0
- package/lib/typescript/src/platform.d.ts +39 -0
- package/lib/typescript/src/platform.d.ts.map +1 -0
- package/lib/typescript/src/types.d.ts +190 -2
- package/lib/typescript/src/types.d.ts.map +1 -1
- package/package.json +8 -4
- package/plugin/withOauthEssentials.js +291 -0
- package/src/NativeOauthEssentials.ts +91 -17
- package/src/errors.ts +49 -0
- package/src/index.tsx +587 -80
- package/src/oauth.ts +140 -0
- package/src/platform.ts +121 -0
- package/src/types.ts +200 -1
package/src/oauth.ts
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { createCredentialError } from './errors';
|
|
2
|
+
import { warnOnce } from './platform';
|
|
3
|
+
import { CredentialError } from './types';
|
|
4
|
+
|
|
5
|
+
export type PkcePair = {
|
|
6
|
+
codeVerifier: string;
|
|
7
|
+
codeChallenge: string;
|
|
8
|
+
state: string;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export type AuthorizationUrlParams = {
|
|
12
|
+
authorizationEndpoint: string;
|
|
13
|
+
clientId: string;
|
|
14
|
+
redirectUri: string;
|
|
15
|
+
scopes?: string[];
|
|
16
|
+
additionalParameters?: Record<string, string>;
|
|
17
|
+
state: string;
|
|
18
|
+
codeChallenge?: string;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
function encodeQuery(params: Record<string, string>): string {
|
|
22
|
+
return Object.keys(params)
|
|
23
|
+
.map(
|
|
24
|
+
(key) => `${encodeURIComponent(key)}=${encodeURIComponent(params[key]!)}`
|
|
25
|
+
)
|
|
26
|
+
.join('&');
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Decodes a query component, keeping it raw when its percent-encoding is malformed (`50%off`), so
|
|
31
|
+
* a provider bug does not turn into an error without `code`.
|
|
32
|
+
*/
|
|
33
|
+
function decodeComponent(value: string): string {
|
|
34
|
+
const spaced = value.replace(/\+/g, ' ');
|
|
35
|
+
try {
|
|
36
|
+
return decodeURIComponent(spaced);
|
|
37
|
+
} catch {
|
|
38
|
+
return spaced;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Set by the library and checked or reused later (state, PKCE, token exchange), so
|
|
44
|
+
* `additionalParameters` cannot override them.
|
|
45
|
+
*/
|
|
46
|
+
export const RESERVED_AUTHORIZATION_PARAMS = [
|
|
47
|
+
'response_type',
|
|
48
|
+
'client_id',
|
|
49
|
+
'redirect_uri',
|
|
50
|
+
'state',
|
|
51
|
+
'code_challenge',
|
|
52
|
+
'code_challenge_method',
|
|
53
|
+
] as const;
|
|
54
|
+
|
|
55
|
+
export function buildAuthorizationUrl(p: AuthorizationUrlParams): string {
|
|
56
|
+
const params: Record<string, string> = {
|
|
57
|
+
response_type: 'code',
|
|
58
|
+
client_id: p.clientId,
|
|
59
|
+
redirect_uri: p.redirectUri,
|
|
60
|
+
state: p.state,
|
|
61
|
+
};
|
|
62
|
+
if (p.scopes && p.scopes.length > 0) {
|
|
63
|
+
params.scope = p.scopes.join(' ');
|
|
64
|
+
}
|
|
65
|
+
if (p.codeChallenge) {
|
|
66
|
+
params.code_challenge = p.codeChallenge;
|
|
67
|
+
params.code_challenge_method = 'S256';
|
|
68
|
+
}
|
|
69
|
+
const reserved: readonly string[] = RESERVED_AUTHORIZATION_PARAMS;
|
|
70
|
+
for (const [key, value] of Object.entries(p.additionalParameters ?? {})) {
|
|
71
|
+
if (reserved.includes(key)) {
|
|
72
|
+
warnOnce(
|
|
73
|
+
'oauthSignIn',
|
|
74
|
+
`additionalParameters.${key}`,
|
|
75
|
+
`additionalParameters.${key} is ignored: the library sets it (use the matching option instead).`
|
|
76
|
+
);
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
params[key] = value;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const separator = p.authorizationEndpoint.includes('?') ? '&' : '?';
|
|
83
|
+
return `${p.authorizationEndpoint}${separator}${encodeQuery(params)}`;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Reads the query and fragment parameters of a redirect url.
|
|
88
|
+
*/
|
|
89
|
+
export function parseRedirectParams(url: string): Record<string, string> {
|
|
90
|
+
const params: Record<string, string> = {};
|
|
91
|
+
const queryStart = url.indexOf('?');
|
|
92
|
+
const hashStart = url.indexOf('#');
|
|
93
|
+
const parts: string[] = [];
|
|
94
|
+
if (queryStart >= 0) {
|
|
95
|
+
parts.push(
|
|
96
|
+
url.slice(queryStart + 1, hashStart > queryStart ? hashStart : undefined)
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
if (hashStart >= 0) {
|
|
100
|
+
parts.push(url.slice(hashStart + 1));
|
|
101
|
+
}
|
|
102
|
+
for (const part of parts) {
|
|
103
|
+
for (const pair of part.split('&')) {
|
|
104
|
+
if (!pair) continue;
|
|
105
|
+
const eq = pair.indexOf('=');
|
|
106
|
+
const key = decodeComponent(eq >= 0 ? pair.slice(0, eq) : pair);
|
|
107
|
+
params[key] = eq >= 0 ? decodeComponent(pair.slice(eq + 1)) : '';
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
return params;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export function getUrlScheme(url: string): string {
|
|
114
|
+
const index = url.indexOf(':');
|
|
115
|
+
if (index <= 0) {
|
|
116
|
+
throw createCredentialError(
|
|
117
|
+
CredentialError.CONFIGURATION_ERROR,
|
|
118
|
+
`Invalid redirect uri: ${url}`
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
return url.slice(0, index);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export function buildTokenRequestBody(p: {
|
|
125
|
+
code: string;
|
|
126
|
+
clientId: string;
|
|
127
|
+
redirectUri: string;
|
|
128
|
+
codeVerifier: string | null;
|
|
129
|
+
}): string {
|
|
130
|
+
const params: Record<string, string> = {
|
|
131
|
+
grant_type: 'authorization_code',
|
|
132
|
+
code: p.code,
|
|
133
|
+
client_id: p.clientId,
|
|
134
|
+
redirect_uri: p.redirectUri,
|
|
135
|
+
};
|
|
136
|
+
if (p.codeVerifier) {
|
|
137
|
+
params.code_verifier = p.codeVerifier;
|
|
138
|
+
}
|
|
139
|
+
return encodeQuery(params);
|
|
140
|
+
}
|
package/src/platform.ts
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import type { GoogleClientId, GoogleSignInOptions } from './types';
|
|
2
|
+
|
|
3
|
+
type OS = 'ios' | 'android' | string;
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Picks the client id the native module of `os` expects.
|
|
7
|
+
*
|
|
8
|
+
* A string is passed as is. With `{ iosClientId, webClientId }`, iOS gets `iosClientId` (or '' so
|
|
9
|
+
* the native side reads `GIDClientID` from Info.plist) and `webClientId` as the default
|
|
10
|
+
* `serverClientId`; Android gets `webClientId` (or '', which rejects with `CONFIGURATION_ERROR`).
|
|
11
|
+
*/
|
|
12
|
+
export function resolveGoogleClientId<T extends GoogleSignInOptions>(
|
|
13
|
+
os: OS,
|
|
14
|
+
clientId: GoogleClientId | null | undefined,
|
|
15
|
+
options: T
|
|
16
|
+
): { clientId: string; options: T } {
|
|
17
|
+
if (typeof clientId === 'string') {
|
|
18
|
+
return { clientId, options };
|
|
19
|
+
}
|
|
20
|
+
const ids = clientId ?? {};
|
|
21
|
+
if (os === 'ios') {
|
|
22
|
+
const resolved = { ...options };
|
|
23
|
+
if (resolved.serverClientId === undefined && ids.webClientId) {
|
|
24
|
+
resolved.serverClientId = ids.webClientId;
|
|
25
|
+
}
|
|
26
|
+
return { clientId: ids.iosClientId ?? '', options: resolved };
|
|
27
|
+
}
|
|
28
|
+
return { clientId: ids.webClientId ?? '', options };
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Splits the `(clientId?, options?)` arguments of the Google methods, which also accept
|
|
33
|
+
* `(options)`: an object with `iosClientId` or `webClientId` is the client id, any other object is
|
|
34
|
+
* the options. Without a client id the native side reads it from the app config (Info.plist,
|
|
35
|
+
* AndroidManifest meta-data or the Firebase files).
|
|
36
|
+
*/
|
|
37
|
+
export function splitGoogleArgs<T extends object>(
|
|
38
|
+
first: GoogleClientId | T | null | undefined,
|
|
39
|
+
second: T | undefined
|
|
40
|
+
): { clientId: GoogleClientId | undefined; options: T | undefined } {
|
|
41
|
+
if (first === null || first === undefined) {
|
|
42
|
+
return { clientId: undefined, options: second };
|
|
43
|
+
}
|
|
44
|
+
if (
|
|
45
|
+
typeof first === 'string' ||
|
|
46
|
+
'iosClientId' in first ||
|
|
47
|
+
'webClientId' in first
|
|
48
|
+
) {
|
|
49
|
+
return { clientId: first as GoogleClientId, options: second };
|
|
50
|
+
}
|
|
51
|
+
return { clientId: undefined, options: first as T };
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Message thrown when the native module is not in the binary: Expo Go (which only ships the Expo
|
|
56
|
+
* SDK native modules) or an app that was not rebuilt after installing the library.
|
|
57
|
+
*/
|
|
58
|
+
export function missingNativeModuleMessage(): string {
|
|
59
|
+
const expo = (globalThis as { expo?: { modules?: Record<string, unknown> } })
|
|
60
|
+
.expo;
|
|
61
|
+
if (expo?.modules?.ExpoGo) {
|
|
62
|
+
return (
|
|
63
|
+
'react-native-oauth-essentials does not work in Expo Go, which only contains the Expo SDK ' +
|
|
64
|
+
'native code. Create a development build instead: `npx expo run:ios` / `npx expo run:android` ' +
|
|
65
|
+
'or `eas build --profile development`.'
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
return (
|
|
69
|
+
'react-native-oauth-essentials: the native module "OauthEssentials" was not found. Rebuild the ' +
|
|
70
|
+
'app after installing the library (run `pod install` in ios/ and build again; reloading Metro is ' +
|
|
71
|
+
'not enough) and make sure the New Architecture is enabled. With Expo, use a development build ' +
|
|
72
|
+
'(Expo Go is not supported).'
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const warned = new Set<string>();
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* In development, warns once per method and option that an option set by the app has no effect on
|
|
80
|
+
* the current platform. `options` must be the options as passed by the app (before defaults).
|
|
81
|
+
*/
|
|
82
|
+
export function warnIgnored(
|
|
83
|
+
method: string,
|
|
84
|
+
platform: string,
|
|
85
|
+
options: object | null | undefined,
|
|
86
|
+
keys: readonly string[]
|
|
87
|
+
): void {
|
|
88
|
+
if (!__DEV__ || !options) {
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
for (const key of keys) {
|
|
92
|
+
if ((options as Record<string, unknown>)[key] !== undefined) {
|
|
93
|
+
warnOnce(
|
|
94
|
+
method,
|
|
95
|
+
key,
|
|
96
|
+
`"${key}" is ignored on ${platformName(platform)}.`
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function platformName(platform: string): string {
|
|
103
|
+
if (platform === 'ios') return 'iOS';
|
|
104
|
+
if (platform === 'android') return 'Android';
|
|
105
|
+
return platform;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* In development, logs `message` once per method and key.
|
|
110
|
+
*/
|
|
111
|
+
export function warnOnce(method: string, key: string, message: string): void {
|
|
112
|
+
if (!__DEV__) {
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
const id = `${method}:${key}`;
|
|
116
|
+
if (warned.has(id)) {
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
warned.add(id);
|
|
120
|
+
console.warn(`[react-native-oauth-essentials] ${method}: ${message}`);
|
|
121
|
+
}
|
package/src/types.ts
CHANGED
|
@@ -1,11 +1,142 @@
|
|
|
1
1
|
export type GoogleSignInOptions = {
|
|
2
|
+
/**
|
|
3
|
+
* Only show accounts that already signed in to the app. [Android only]
|
|
4
|
+
*/
|
|
2
5
|
authorizedAccounts?: boolean;
|
|
6
|
+
/**
|
|
7
|
+
* Automatically sign in when a single authorized account is available. [Android only]
|
|
8
|
+
*/
|
|
3
9
|
autoSelectEnabled?: boolean;
|
|
10
|
+
/**
|
|
11
|
+
* Android UI flow. `bottomSheet` (default) shows the Credential Manager sheet and, unless
|
|
12
|
+
* `authorizedAccounts` is set, falls back to `button` when no credential is available
|
|
13
|
+
* (no account on the device or the sheet is in cooldown after being dismissed).
|
|
14
|
+
* `button` always shows the "Sign in with Google" flow, which is what a sign-in button tap
|
|
15
|
+
* should use. [Android only]
|
|
16
|
+
*/
|
|
17
|
+
mode?: 'bottomSheet' | 'button';
|
|
18
|
+
/**
|
|
19
|
+
* Nonce embedded as-is in the returned idToken, so your backend can prevent replay attacks.
|
|
20
|
+
* Ignored by `googleSilentSignIn` on iOS.
|
|
21
|
+
*/
|
|
22
|
+
nonce?: string;
|
|
23
|
+
/**
|
|
24
|
+
* Email to preselect in the Google page. [iOS only]
|
|
25
|
+
*/
|
|
26
|
+
hint?: string;
|
|
27
|
+
/**
|
|
28
|
+
* Restricts sign in to a Google Workspace domain. On Android it only applies to the
|
|
29
|
+
* "Sign in with Google" (`button`) flow and to the authorization step, not to the bottom sheet.
|
|
30
|
+
*/
|
|
31
|
+
hostedDomain?: string;
|
|
32
|
+
/**
|
|
33
|
+
* Additional OAuth scopes the user must grant.
|
|
34
|
+
* iOS: requested during sign in; `accessToken` and `grantedScopes` are always returned.
|
|
35
|
+
* Android: requested in a second step (Authorization API, may show a consent screen); without
|
|
36
|
+
* `scopes`/`offlineAccess`, `accessToken` and `grantedScopes` are null.
|
|
37
|
+
*/
|
|
38
|
+
scopes?: string[];
|
|
39
|
+
/**
|
|
40
|
+
* Android: requests a `serverAuthCode` (for `serverClientId`, or the main client id) your backend
|
|
41
|
+
* can exchange for refresh tokens. iOS: no effect, `serverAuthCode` is returned whenever
|
|
42
|
+
* `serverClientId` is set.
|
|
43
|
+
*/
|
|
44
|
+
offlineAccess?: boolean;
|
|
45
|
+
/**
|
|
46
|
+
* iOS: web (server) client id. Makes it the idToken audience and returns a `serverAuthCode`.
|
|
47
|
+
* Android: client id the `serverAuthCode` is issued for (defaults to the main client id).
|
|
48
|
+
*/
|
|
49
|
+
serverClientId?: string;
|
|
4
50
|
};
|
|
5
51
|
|
|
52
|
+
/**
|
|
53
|
+
* Google OAuth client ids per platform, all from the same Google Cloud project.
|
|
54
|
+
*
|
|
55
|
+
* Both are optional: a missing id is read from the app config, which the Expo plugin writes (from
|
|
56
|
+
* its options or the Firebase files).
|
|
57
|
+
*/
|
|
58
|
+
export type GoogleClientIds = {
|
|
59
|
+
/**
|
|
60
|
+
* iOS client id (created with the iOS bundle id). Used on iOS only. When missing, the `GIDClientID`
|
|
61
|
+
* key of Info.plist is used, then `CLIENT_ID` of GoogleService-Info.plist.
|
|
62
|
+
*/
|
|
63
|
+
iosClientId?: string;
|
|
64
|
+
/**
|
|
65
|
+
* Web client id. Android: the client id passed to Credential Manager; when missing, the
|
|
66
|
+
* `com.oauthessentials.GOOGLE_WEB_CLIENT_ID` meta-data of AndroidManifest is used, then the
|
|
67
|
+
* `default_web_client_id` string generated by the Firebase `google-services` Gradle plugin.
|
|
68
|
+
* iOS: the default `serverClientId` (idToken audience); when missing, the `GIDServerClientID` key
|
|
69
|
+
* of Info.plist is used.
|
|
70
|
+
*/
|
|
71
|
+
webClientId?: string;
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* A {@link GoogleClientIds} object, or a single client id string, used as is on both platforms
|
|
76
|
+
* (it must be the iOS client id on iOS and the web client id on Android).
|
|
77
|
+
*/
|
|
78
|
+
export type GoogleClientId = string | GoogleClientIds;
|
|
79
|
+
|
|
80
|
+
export type AppleSignInOptions = {
|
|
81
|
+
/**
|
|
82
|
+
* Nonce passed as-is to Apple and embedded in the idToken. Firebase and Supabase expect the
|
|
83
|
+
* SHA-256 of the raw nonce here. [iOS only, on Android put it in your `androidWebUrl`]
|
|
84
|
+
*/
|
|
85
|
+
nonce?: string;
|
|
86
|
+
/**
|
|
87
|
+
* Opaque value returned in the credential. [iOS only]
|
|
88
|
+
*/
|
|
89
|
+
state?: string;
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
export type HybridSignInOptions = GoogleSignInOptions;
|
|
93
|
+
|
|
6
94
|
export type PasskeyOptions = {
|
|
95
|
+
/**
|
|
96
|
+
* WebAuthn options JSON from your server: `PublicKeyCredentialCreationOptions` for
|
|
97
|
+
* `createPassKey`, `PublicKeyCredentialRequestOptions` for `getPassKey`.
|
|
98
|
+
*/
|
|
7
99
|
requestJson: string;
|
|
8
|
-
|
|
100
|
+
/**
|
|
101
|
+
* Only offer credentials already available on the device. [Android only, iOS modal requests
|
|
102
|
+
* always behave this way]
|
|
103
|
+
*/
|
|
104
|
+
preferImmediatelyAvailableCredentials?: boolean;
|
|
105
|
+
/**
|
|
106
|
+
* `autofill` shows passkeys in the QuickType bar of a text field with
|
|
107
|
+
* `textContentType="username"` instead of a modal sheet. [iOS 16+ only]
|
|
108
|
+
*/
|
|
109
|
+
mediation?: 'modal' | 'autofill';
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
export type OAuthSignInOptions = {
|
|
113
|
+
authorizationEndpoint: string;
|
|
114
|
+
clientId: string;
|
|
115
|
+
/**
|
|
116
|
+
* Defaults to `OAUTH_REDIRECT_URI` (`<bundle or application id>://oauth/callback`).
|
|
117
|
+
*/
|
|
118
|
+
redirectUri?: string;
|
|
119
|
+
scopes?: string[];
|
|
120
|
+
/**
|
|
121
|
+
* Extra authorization request parameters (e.g. `prompt`, `login_hint`, `nonce`). They may
|
|
122
|
+
* override `scope`, but `response_type`, `client_id`, `redirect_uri`, `state`, `code_challenge`
|
|
123
|
+
* and `code_challenge_method` are set by the library and ignored here (with a warning in
|
|
124
|
+
* development).
|
|
125
|
+
*/
|
|
126
|
+
additionalParameters?: Record<string, string>;
|
|
127
|
+
/**
|
|
128
|
+
* When set, the authorization code is exchanged for tokens on the device.
|
|
129
|
+
* Leave it out to exchange the code on your backend (recommended for confidential clients).
|
|
130
|
+
*/
|
|
131
|
+
tokenEndpoint?: string;
|
|
132
|
+
/**
|
|
133
|
+
* Defaults to true.
|
|
134
|
+
*/
|
|
135
|
+
usePKCE?: boolean;
|
|
136
|
+
/**
|
|
137
|
+
* Do not share cookies with the browser. [iOS only]
|
|
138
|
+
*/
|
|
139
|
+
prefersEphemeralSession?: boolean;
|
|
9
140
|
};
|
|
10
141
|
|
|
11
142
|
export type PassKeyCredentialResult = {
|
|
@@ -24,13 +155,20 @@ export type PasswordCredentialResult = {
|
|
|
24
155
|
export type GoogleIdCredentialResult = {
|
|
25
156
|
type: CredentialsType.GOOGLE_ID;
|
|
26
157
|
data: {
|
|
158
|
+
/** iOS: Google user id (the idToken `sub`). Android: the account email. */
|
|
27
159
|
id: string;
|
|
28
160
|
idToken: string;
|
|
29
161
|
displayName: string;
|
|
30
162
|
givenName: string;
|
|
31
163
|
familyName: string;
|
|
164
|
+
email?: string;
|
|
165
|
+
/** iOS: 200px picture url or "". */
|
|
32
166
|
profilePictureUri?: string | null;
|
|
167
|
+
/** Android only. */
|
|
33
168
|
phoneNumber?: string | null;
|
|
169
|
+
accessToken?: string | null;
|
|
170
|
+
serverAuthCode?: string | null;
|
|
171
|
+
grantedScopes?: string[] | null;
|
|
34
172
|
};
|
|
35
173
|
};
|
|
36
174
|
|
|
@@ -48,6 +186,7 @@ export type AppleIdCredentialResult = {
|
|
|
48
186
|
email: string;
|
|
49
187
|
fullName: string;
|
|
50
188
|
likelyReal: boolean;
|
|
189
|
+
state?: string | null;
|
|
51
190
|
};
|
|
52
191
|
};
|
|
53
192
|
|
|
@@ -62,6 +201,30 @@ export type WebAppleIdCredentialResult = {
|
|
|
62
201
|
};
|
|
63
202
|
};
|
|
64
203
|
|
|
204
|
+
export type OAuthCredentialResult = {
|
|
205
|
+
type: CredentialsType.OAUTH;
|
|
206
|
+
data: {
|
|
207
|
+
code: string;
|
|
208
|
+
state: string;
|
|
209
|
+
redirectUri: string;
|
|
210
|
+
codeVerifier: string | null;
|
|
211
|
+
/** All parameters received in the redirect url. */
|
|
212
|
+
params: Record<string, string>;
|
|
213
|
+
/** Token endpoint response, only when `tokenEndpoint` is set. */
|
|
214
|
+
tokens: Record<string, unknown> | null;
|
|
215
|
+
};
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
export type CredentialSuccessEvent = {
|
|
219
|
+
type: string;
|
|
220
|
+
data: Object;
|
|
221
|
+
};
|
|
222
|
+
|
|
223
|
+
export type CredentialFailureEvent = {
|
|
224
|
+
code: CredentialErrorCode;
|
|
225
|
+
message: string;
|
|
226
|
+
};
|
|
227
|
+
|
|
65
228
|
export enum CredentialsType {
|
|
66
229
|
GOOGLE_ID = 'GOOGLE_ID', // GoogleId credentials type
|
|
67
230
|
PASSWORD = 'PASSWORD', // Password credentials type
|
|
@@ -69,10 +232,46 @@ export enum CredentialsType {
|
|
|
69
232
|
WEB_APPLE_ID = 'WEB_APPLE_ID', // Android AppleId credentials type
|
|
70
233
|
CANCELLED = 'CANCELLED', // type when the user cancels it
|
|
71
234
|
PASSKEY = 'PASSKEY', // Passkey credential type
|
|
235
|
+
OAUTH = 'OAUTH', // Generic OAuth2/OIDC authorization code
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
export enum AppleIdCredentialState {
|
|
239
|
+
AUTHORIZED = 'AUTHORIZED',
|
|
240
|
+
REVOKED = 'REVOKED',
|
|
241
|
+
NOT_FOUND = 'NOT_FOUND',
|
|
242
|
+
TRANSFERRED = 'TRANSFERRED',
|
|
72
243
|
}
|
|
73
244
|
|
|
74
245
|
export enum CredentialError {
|
|
246
|
+
/**
|
|
247
|
+
* @deprecated Never thrown: missing Play Services rejects with `NOT_SUPPORTED_ERROR`.
|
|
248
|
+
*/
|
|
75
249
|
NO_PLAY_SERVICES_ERROR = 'NO_PLAY_SERVICES_ERROR',
|
|
250
|
+
/** No Android activity, or no iOS view controller attached to a window, to present the UI. */
|
|
76
251
|
NO_ACTIVITY_ERROR = 'NO_ACTIVITY_ERROR',
|
|
252
|
+
/** The provider failed or returned something unexpected; `message` has the native error. */
|
|
77
253
|
INVALID_RESULT_ERROR = 'INVALID_RESULT_ERROR',
|
|
254
|
+
/** There is no credential to return (no account / passkey / previous sign in). */
|
|
255
|
+
NO_SIGN_IN_AVAILABLE = 'NO_SIGN_IN_AVAILABLE',
|
|
256
|
+
/** iOS: the same method (or method group) is still waiting for the previous call. */
|
|
257
|
+
SIMULTANEOUS_CALL_ERROR = 'SIMULTANEOUS_CALL_ERROR',
|
|
258
|
+
/** The OS version, missing Play Services or the platform does not support the method. */
|
|
259
|
+
NOT_SUPPORTED_ERROR = 'NOT_SUPPORTED_ERROR',
|
|
260
|
+
/** The browser session could not be opened (app in background, Guided Access, no browser). */
|
|
261
|
+
BROWSER_UNAVAILABLE = 'BROWSER_UNAVAILABLE',
|
|
262
|
+
/**
|
|
263
|
+
* The app is misconfigured: missing Google client id, missing iOS URL scheme (the message has
|
|
264
|
+
* the exact scheme to add) or an invalid `redirectUri`.
|
|
265
|
+
*/
|
|
266
|
+
CONFIGURATION_ERROR = 'CONFIGURATION_ERROR',
|
|
267
|
+
/** `oauthSignIn`: the token endpoint request failed (offline, DNS, TLS...). */
|
|
268
|
+
NETWORK_ERROR = 'NETWORK_ERROR',
|
|
78
269
|
}
|
|
270
|
+
|
|
271
|
+
/** A {@link CredentialError} value, as an enum member or its string. */
|
|
272
|
+
export type CredentialErrorCode = `${CredentialError}`;
|
|
273
|
+
|
|
274
|
+
/** Every promise of the library rejects with an `Error` that has one of these codes. */
|
|
275
|
+
export type OauthEssentialsError<
|
|
276
|
+
C extends CredentialErrorCode = CredentialErrorCode
|
|
277
|
+
> = Error & { code: C };
|