@authowl/react-native 0.2.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/LICENSE +21 -0
- package/README.md +225 -0
- package/THIRD_PARTY_NOTICES.md +8 -0
- package/dist/index.cjs +1193 -0
- package/dist/index.d.cts +654 -0
- package/dist/index.d.ts +654 -0
- package/dist/index.js +1160 -0
- package/package.json +69 -0
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,654 @@
|
|
|
1
|
+
import { PublicConfig, NativeAuthClient, NativePasskeyCapableClient, PasskeyCeremonyClientFactory, NativeSocialSignInOptions, AuthActionResult, SocialAuthData, AuthUser, AuthSession, HasParams, SessionState, Organization, PasskeyRegistrationResponse, PasskeyAuthenticationResponse } from '@authowl/core/native';
|
|
2
|
+
export { AuthSession, AuthUser, HasParams, NativeAuthClient, NativeSocialSignInOptions, OrganizationMembership, SessionState, NativeSocialSignInOptions as SocialIdTokenSignInOptions, sessionCookieName } from '@authowl/core/native';
|
|
3
|
+
import * as react from 'react';
|
|
4
|
+
import { ReactNode } from 'react';
|
|
5
|
+
import { Locale, ServerErrorInput, MessageKey, MessageParams } from '@authowl/core/i18n';
|
|
6
|
+
export { Locale, MessageKey, MessageParams } from '@authowl/core/i18n';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Where a native app keeps its session.
|
|
10
|
+
*
|
|
11
|
+
* The session cookie is a bearer credential: anything holding it IS the signed-in
|
|
12
|
+
* user until it expires. On a phone that means the OS keychain / keystore, not
|
|
13
|
+
* AsyncStorage, which is plain unencrypted files any process with the sandbox
|
|
14
|
+
* can read. `@authowl/expo` supplies an `expo-secure-store` adapter; bare React
|
|
15
|
+
* Native apps typically use `react-native-keychain`.
|
|
16
|
+
*/
|
|
17
|
+
interface SecureStorage {
|
|
18
|
+
getItem(key: string): Promise<string | null>;
|
|
19
|
+
setItem(key: string, value: string): Promise<void>;
|
|
20
|
+
removeItem(key: string): Promise<void>;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* An in-memory store, for tests and for previews where persistence is unwanted.
|
|
24
|
+
*
|
|
25
|
+
* Explicitly NOT a default: silently falling back to memory would make sign-in
|
|
26
|
+
* appear to work and then drop the session on the next app launch, which is a
|
|
27
|
+
* confusing bug to chase. Callers must choose their storage.
|
|
28
|
+
*/
|
|
29
|
+
declare class MemoryStorage implements SecureStorage {
|
|
30
|
+
private readonly entries;
|
|
31
|
+
getItem(key: string): Promise<string | null>;
|
|
32
|
+
setItem(key: string, value: string): Promise<void>;
|
|
33
|
+
removeItem(key: string): Promise<void>;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** Building the AuthOwl client for a native app. */
|
|
37
|
+
|
|
38
|
+
interface AuthOwlNativeConfig {
|
|
39
|
+
/** The project's `pk_live_…` / `pk_test_…` key. Secret keys are refused. */
|
|
40
|
+
publishableKey: string;
|
|
41
|
+
/** The AuthOwl API origin, e.g. `https://api.authowl.dev`. */
|
|
42
|
+
apiUrl: string;
|
|
43
|
+
/** Where the session cookie is persisted. Use the OS keychain in production. */
|
|
44
|
+
storage: SecureStorage;
|
|
45
|
+
/** Defaults to the global fetch. Injectable for tests. */
|
|
46
|
+
fetchImpl?: typeof fetch;
|
|
47
|
+
/** Called after any action that mutates the session. */
|
|
48
|
+
onSessionMutation?: () => void;
|
|
49
|
+
/**
|
|
50
|
+
* Platform passkey ceremony, from `createNativePasskeys()`.
|
|
51
|
+
*
|
|
52
|
+
* Omit it and the passkey methods are absent from the client's TYPE, so an
|
|
53
|
+
* app cannot call a prompt the runtime could never show.
|
|
54
|
+
*/
|
|
55
|
+
passkeys?: PasskeyCeremonyClientFactory;
|
|
56
|
+
}
|
|
57
|
+
interface AuthOwlNativeConfigWithPasskeys extends AuthOwlNativeConfig {
|
|
58
|
+
passkeys: PasskeyCeremonyClientFactory;
|
|
59
|
+
}
|
|
60
|
+
interface AuthOwlNativeBase {
|
|
61
|
+
projectId: string;
|
|
62
|
+
getPublicConfig: () => Promise<PublicConfig>;
|
|
63
|
+
}
|
|
64
|
+
interface AuthOwlNative extends AuthOwlNativeBase {
|
|
65
|
+
client: NativeAuthClient | NativePasskeyCapableClient;
|
|
66
|
+
}
|
|
67
|
+
interface AuthOwlPasskeyNative extends AuthOwlNativeBase {
|
|
68
|
+
client: NativePasskeyCapableClient;
|
|
69
|
+
}
|
|
70
|
+
interface AuthOwlHeadlessNative extends AuthOwlNativeBase {
|
|
71
|
+
client: NativeAuthClient;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Build a native AuthOwl client with session persistence wired up.
|
|
75
|
+
*
|
|
76
|
+
* The publishable key is decoded up front so a `sk_` key fails HERE, loudly, at
|
|
77
|
+
* startup - rather than being shipped inside an app binary where it cannot be
|
|
78
|
+
* rotated out of users' hands.
|
|
79
|
+
*/
|
|
80
|
+
declare function createAuthOwlNative(config: AuthOwlNativeConfigWithPasskeys): AuthOwlPasskeyNative;
|
|
81
|
+
declare function createAuthOwlNative(config: AuthOwlNativeConfig & {
|
|
82
|
+
passkeys?: undefined;
|
|
83
|
+
}): AuthOwlHeadlessNative;
|
|
84
|
+
declare function createAuthOwlNative(config: AuthOwlNativeConfig): AuthOwlNative;
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* A one-cookie jar backed by secure storage.
|
|
88
|
+
*
|
|
89
|
+
* Why this exists: the AuthOwl server authenticates with a session COOKIE, and
|
|
90
|
+
* the browser SDK simply lets the browser's cookie jar do the work. React Native
|
|
91
|
+
* has no dependable equivalent - its `fetch` cookie behaviour differs between
|
|
92
|
+
* iOS and Android, is invisible to JS, and does not reliably survive an app
|
|
93
|
+
* restart or update. So the native SDK keeps the one cookie it cares about
|
|
94
|
+
* itself: replay it on every request, and re-capture it whenever the server
|
|
95
|
+
* rotates it.
|
|
96
|
+
*
|
|
97
|
+
* This talks to the server exactly as the browser does, so no server-side
|
|
98
|
+
* "native mode" is required.
|
|
99
|
+
*/
|
|
100
|
+
|
|
101
|
+
interface CookieJarOptions {
|
|
102
|
+
/** Where the session cookie is persisted. */
|
|
103
|
+
storage: SecureStorage;
|
|
104
|
+
/** The project id, used to derive the exact cookie name the server sets. */
|
|
105
|
+
projectId: string;
|
|
106
|
+
/**
|
|
107
|
+
* Whether the server issues `__Secure-` cookies. Derive it from the API URL's
|
|
108
|
+
* scheme (`https:` => true) - it must match the SERVER, not the client.
|
|
109
|
+
*/
|
|
110
|
+
secure: boolean;
|
|
111
|
+
/** Defaults to the global fetch. Injectable for tests. */
|
|
112
|
+
fetchImpl?: typeof fetch;
|
|
113
|
+
}
|
|
114
|
+
/** The storage key under which the raw cookie value is kept. */
|
|
115
|
+
declare function sessionStorageKey(projectId: string): string;
|
|
116
|
+
/**
|
|
117
|
+
* Parse the cookie value the server set for `name`, if this response sets it.
|
|
118
|
+
*
|
|
119
|
+
* Deliberately hand-rolled and narrow: it looks for ONE cookie by exact name and
|
|
120
|
+
* ignores every attribute (`Path`, `HttpOnly`, `SameSite`, …). A general cookie
|
|
121
|
+
* jar would have to model domains and paths, which is a large amount of surface
|
|
122
|
+
* for a client that only ever talks to one origin.
|
|
123
|
+
*
|
|
124
|
+
* Returns `null` when the response does not set the cookie, and the empty string
|
|
125
|
+
* when the server clears it (sign-out), which the caller treats as a deletion.
|
|
126
|
+
*/
|
|
127
|
+
declare function readSetCookie(header: readonly string[] | string | null, name: string): string | null;
|
|
128
|
+
/**
|
|
129
|
+
* Wrap `fetch` so the session cookie is replayed from, and captured into,
|
|
130
|
+
* secure storage.
|
|
131
|
+
*/
|
|
132
|
+
declare function createCookieJarFetch(options: CookieJarOptions): typeof fetch;
|
|
133
|
+
|
|
134
|
+
/** Native social sign-in through a provider-issued ID token. */
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Exchange an ID token obtained from a provider's native SDK for an AuthOwl
|
|
138
|
+
* session. The cookie jar captures the session cookie from this same response,
|
|
139
|
+
* so no browser-cookie bridge or deep-link credential is required.
|
|
140
|
+
*/
|
|
141
|
+
declare function signInWithSocialIdToken(client: NativeAuthClient, options: NativeSocialSignInOptions): Promise<AuthActionResult<SocialAuthData>>;
|
|
142
|
+
|
|
143
|
+
/** React context and hooks for a native AuthOwl app. */
|
|
144
|
+
|
|
145
|
+
type PublicConfigState = 'loading' | 'ready' | 'error';
|
|
146
|
+
interface AuthOwlProviderProps extends AuthOwlNativeConfig {
|
|
147
|
+
children?: ReactNode;
|
|
148
|
+
/**
|
|
149
|
+
* Locale for the built-in components. Defaults to English.
|
|
150
|
+
*
|
|
151
|
+
* Not auto-detected from the device: a phone set to Arabic does not imply the
|
|
152
|
+
* app is localized to Arabic, and silently switching the auth screens away
|
|
153
|
+
* from the rest of the app is worse than defaulting. Pass the locale the app
|
|
154
|
+
* has already resolved.
|
|
155
|
+
*/
|
|
156
|
+
locale?: Locale;
|
|
157
|
+
}
|
|
158
|
+
/** Provides the AuthOwl client to a native React tree. */
|
|
159
|
+
declare function AuthOwlProvider(props: AuthOwlProviderProps): ReactNode;
|
|
160
|
+
/** The locale the provider resolved, for the built-in components. */
|
|
161
|
+
declare function useAuthOwlLocale(): Locale;
|
|
162
|
+
/** Native-safe sign-in, account, organization, and passkey-management actions. */
|
|
163
|
+
declare function useAuthOwlClient(): NativeAuthClient | NativePasskeyCapableClient;
|
|
164
|
+
/** Project capabilities and legal policy used by the built-in components. */
|
|
165
|
+
declare function usePublicConfig(): {
|
|
166
|
+
data: PublicConfig | null;
|
|
167
|
+
state: PublicConfigState;
|
|
168
|
+
isLoading: boolean;
|
|
169
|
+
};
|
|
170
|
+
/** The live session state, re-rendering whenever the session changes. */
|
|
171
|
+
declare function useSession(): SessionState;
|
|
172
|
+
interface UseAuthResult {
|
|
173
|
+
isLoaded: boolean;
|
|
174
|
+
isSignedIn: boolean;
|
|
175
|
+
user: AuthUser | null;
|
|
176
|
+
session: AuthSession | null;
|
|
177
|
+
signOut: () => Promise<void>;
|
|
178
|
+
/**
|
|
179
|
+
* Advisory permission check over the CURRENT session claim.
|
|
180
|
+
*
|
|
181
|
+
* Advisory only: this is for hiding UI the user cannot use. The real boundary
|
|
182
|
+
* is server-side, over a verified token - never gate anything that matters on
|
|
183
|
+
* a client-side answer.
|
|
184
|
+
*/
|
|
185
|
+
has: (params: HasParams) => boolean;
|
|
186
|
+
hasPermission: (params: {
|
|
187
|
+
permission: string;
|
|
188
|
+
}) => boolean;
|
|
189
|
+
}
|
|
190
|
+
/** The primary hook: who is signed in, and what may they do. */
|
|
191
|
+
declare function useAuth(): UseAuthResult;
|
|
192
|
+
/** The signed-in user, or null. */
|
|
193
|
+
declare function useUser(): AuthUser | null;
|
|
194
|
+
/** Exchange an ID token from a provider's native SDK for an AuthOwl session. */
|
|
195
|
+
declare function useSocialSignIn(): (options: NativeSocialSignInOptions) => Promise<AuthActionResult<SocialAuthData>>;
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Visual tokens for the built-in components.
|
|
199
|
+
*
|
|
200
|
+
* Deliberately small and overridable rather than a full theming engine: an app
|
|
201
|
+
* that wants its own look should compose the headless hooks, not fight a
|
|
202
|
+
* cascade. These exist so the drop-in screens look deliberate out of the box.
|
|
203
|
+
*/
|
|
204
|
+
interface AuthOwlTheme {
|
|
205
|
+
accent: string;
|
|
206
|
+
accentText: string;
|
|
207
|
+
/** Readable inline-link color; defaults to `accent` for custom themes. */
|
|
208
|
+
link?: string;
|
|
209
|
+
text: string;
|
|
210
|
+
mutedText: string;
|
|
211
|
+
background: string;
|
|
212
|
+
surface: string;
|
|
213
|
+
border: string;
|
|
214
|
+
danger: string;
|
|
215
|
+
radius: number;
|
|
216
|
+
spacing: number;
|
|
217
|
+
}
|
|
218
|
+
declare const defaultTheme: AuthOwlTheme;
|
|
219
|
+
declare const darkTheme: AuthOwlTheme;
|
|
220
|
+
/** Build the stylesheet for a theme. Memoize per theme at the call site. */
|
|
221
|
+
declare function createStyles(theme: AuthOwlTheme): {
|
|
222
|
+
container: {
|
|
223
|
+
gap: number;
|
|
224
|
+
backgroundColor: string;
|
|
225
|
+
};
|
|
226
|
+
title: {
|
|
227
|
+
fontSize: number;
|
|
228
|
+
fontWeight: string;
|
|
229
|
+
color: string;
|
|
230
|
+
};
|
|
231
|
+
label: {
|
|
232
|
+
fontSize: number;
|
|
233
|
+
fontWeight: string;
|
|
234
|
+
color: string;
|
|
235
|
+
};
|
|
236
|
+
field: {
|
|
237
|
+
gap: number;
|
|
238
|
+
};
|
|
239
|
+
input: {
|
|
240
|
+
borderWidth: number;
|
|
241
|
+
borderColor: string;
|
|
242
|
+
borderRadius: number;
|
|
243
|
+
paddingHorizontal: number;
|
|
244
|
+
paddingVertical: number;
|
|
245
|
+
fontSize: number;
|
|
246
|
+
color: string;
|
|
247
|
+
backgroundColor: string;
|
|
248
|
+
};
|
|
249
|
+
inputInvalid: {
|
|
250
|
+
borderColor: string;
|
|
251
|
+
};
|
|
252
|
+
button: {
|
|
253
|
+
borderRadius: number;
|
|
254
|
+
paddingVertical: number;
|
|
255
|
+
alignItems: string;
|
|
256
|
+
backgroundColor: string;
|
|
257
|
+
};
|
|
258
|
+
buttonDisabled: {
|
|
259
|
+
opacity: number;
|
|
260
|
+
};
|
|
261
|
+
buttonText: {
|
|
262
|
+
color: string;
|
|
263
|
+
fontSize: number;
|
|
264
|
+
fontWeight: string;
|
|
265
|
+
};
|
|
266
|
+
link: {
|
|
267
|
+
color: string;
|
|
268
|
+
fontSize: number;
|
|
269
|
+
};
|
|
270
|
+
consentRow: {
|
|
271
|
+
flexDirection: string;
|
|
272
|
+
alignItems: string;
|
|
273
|
+
gap: number;
|
|
274
|
+
};
|
|
275
|
+
consentToggle: {
|
|
276
|
+
minWidth: number;
|
|
277
|
+
height: number;
|
|
278
|
+
alignItems: string;
|
|
279
|
+
justifyContent: string;
|
|
280
|
+
};
|
|
281
|
+
consentBox: {
|
|
282
|
+
width: number;
|
|
283
|
+
height: number;
|
|
284
|
+
alignItems: string;
|
|
285
|
+
justifyContent: string;
|
|
286
|
+
borderWidth: number;
|
|
287
|
+
borderColor: string;
|
|
288
|
+
borderRadius: number;
|
|
289
|
+
backgroundColor: string;
|
|
290
|
+
};
|
|
291
|
+
consentBoxChecked: {
|
|
292
|
+
borderColor: string;
|
|
293
|
+
backgroundColor: string;
|
|
294
|
+
};
|
|
295
|
+
consentBoxDisabled: {
|
|
296
|
+
opacity: number;
|
|
297
|
+
};
|
|
298
|
+
consentCheck: {
|
|
299
|
+
color: string;
|
|
300
|
+
fontSize: number;
|
|
301
|
+
fontWeight: string;
|
|
302
|
+
lineHeight: number;
|
|
303
|
+
};
|
|
304
|
+
consentText: {
|
|
305
|
+
flex: number;
|
|
306
|
+
color: string;
|
|
307
|
+
fontSize: number;
|
|
308
|
+
lineHeight: number;
|
|
309
|
+
};
|
|
310
|
+
consentLink: {
|
|
311
|
+
color: string;
|
|
312
|
+
textDecorationLine: string;
|
|
313
|
+
};
|
|
314
|
+
error: {
|
|
315
|
+
color: string;
|
|
316
|
+
fontSize: number;
|
|
317
|
+
};
|
|
318
|
+
};
|
|
319
|
+
|
|
320
|
+
interface SignInProps {
|
|
321
|
+
/** Called once a session exists. */
|
|
322
|
+
onSignedIn?: () => void;
|
|
323
|
+
/** Called when valid credentials require an MFA challenge before a session exists. */
|
|
324
|
+
onSecondFactorRequired?: () => void;
|
|
325
|
+
/** Rendered as a link under the form, when provided. */
|
|
326
|
+
onForgotPassword?: () => void;
|
|
327
|
+
theme?: AuthOwlTheme;
|
|
328
|
+
}
|
|
329
|
+
/**
|
|
330
|
+
* Email and password sign-in.
|
|
331
|
+
*
|
|
332
|
+
* Social sign-in is intentionally NOT rendered here. It needs a provider ID
|
|
333
|
+
* token from a native SDK the app has to configure itself, so a button that
|
|
334
|
+
* cannot work without that wiring would be a broken affordance. Use
|
|
335
|
+
* `useSocialSignIn()` alongside this screen.
|
|
336
|
+
*/
|
|
337
|
+
declare function SignIn({ onSignedIn, onSecondFactorRequired, onForgotPassword, theme, }: SignInProps): react.JSX.Element | null;
|
|
338
|
+
|
|
339
|
+
interface SignUpProps {
|
|
340
|
+
/**
|
|
341
|
+
* Called when sign-up succeeds.
|
|
342
|
+
*
|
|
343
|
+
* `sessionCreated` is false when the project requires email verification
|
|
344
|
+
* first. The caller decides what happens next, because "check your email" and
|
|
345
|
+
* "you are signed in" are different screens.
|
|
346
|
+
*/
|
|
347
|
+
onSignedUp?: (result: {
|
|
348
|
+
sessionCreated: boolean;
|
|
349
|
+
}) => void;
|
|
350
|
+
/** Collect first and last name instead of a single display name. */
|
|
351
|
+
structuredName?: boolean;
|
|
352
|
+
theme?: AuthOwlTheme;
|
|
353
|
+
}
|
|
354
|
+
/** Create an account with an email address and password. */
|
|
355
|
+
declare function SignUp({ onSignedUp, structuredName, theme }: SignUpProps): react.JSX.Element | null;
|
|
356
|
+
|
|
357
|
+
interface EmailOtpFormProps {
|
|
358
|
+
onSignedIn?: () => void;
|
|
359
|
+
theme?: AuthOwlTheme;
|
|
360
|
+
}
|
|
361
|
+
/**
|
|
362
|
+
* Two stages in one screen: request a code, then verify it.
|
|
363
|
+
*
|
|
364
|
+
* Kept together because the second stage is meaningless without the address
|
|
365
|
+
* entered in the first, and splitting them across screens loses that context on
|
|
366
|
+
* a back navigation.
|
|
367
|
+
*/
|
|
368
|
+
declare function EmailOtpForm({ onSignedIn, theme }: EmailOtpFormProps): react.JSX.Element;
|
|
369
|
+
|
|
370
|
+
interface OrganizationSwitcherProps {
|
|
371
|
+
/** Called after the active organization changes, including to personal. */
|
|
372
|
+
onSwitched?: (organization: Organization | null) => void;
|
|
373
|
+
/**
|
|
374
|
+
* Offer a "personal account" row that clears the active organization.
|
|
375
|
+
* Off by default: many apps require an organization context to function.
|
|
376
|
+
*/
|
|
377
|
+
allowPersonal?: boolean;
|
|
378
|
+
theme?: AuthOwlTheme;
|
|
379
|
+
}
|
|
380
|
+
/**
|
|
381
|
+
* Lists the caller's organizations and switches between them.
|
|
382
|
+
*
|
|
383
|
+
* Reads the ACTIVE organization from the session rather than tracking it
|
|
384
|
+
* locally. Switching re-mints the session claim server-side, so local state
|
|
385
|
+
* would be a second source of truth that drifts the moment anything else
|
|
386
|
+
* changes the active org.
|
|
387
|
+
*/
|
|
388
|
+
declare function OrganizationSwitcher({ onSwitched, allowPersonal, theme, }: OrganizationSwitcherProps): react.JSX.Element | null;
|
|
389
|
+
|
|
390
|
+
interface PasskeyEnrollmentProps {
|
|
391
|
+
/** Suggested credential name, shown in the platform's list. */
|
|
392
|
+
name?: string;
|
|
393
|
+
onEnrolled?: () => void;
|
|
394
|
+
/** Rendered as a skip link when provided. */
|
|
395
|
+
onSkip?: () => void;
|
|
396
|
+
theme?: AuthOwlTheme;
|
|
397
|
+
}
|
|
398
|
+
/**
|
|
399
|
+
* Offer to create a passkey.
|
|
400
|
+
*
|
|
401
|
+
* Renders nothing without a passkey adapter, so it is safe to drop into a
|
|
402
|
+
* post-sign-up flow that also runs on projects with passkeys disabled.
|
|
403
|
+
*/
|
|
404
|
+
declare function PasskeyEnrollment({ name, onEnrolled, onSkip, theme, }: PasskeyEnrollmentProps): react.JSX.Element | null;
|
|
405
|
+
interface PasskeySignInButtonProps {
|
|
406
|
+
onSignedIn?: () => void;
|
|
407
|
+
theme?: AuthOwlTheme;
|
|
408
|
+
}
|
|
409
|
+
/** Sign in with an already-enrolled passkey. */
|
|
410
|
+
declare function PasskeySignInButton({ onSignedIn, theme, }: PasskeySignInButtonProps): react.JSX.Element | null;
|
|
411
|
+
|
|
412
|
+
/**
|
|
413
|
+
* Platform passkeys on a phone.
|
|
414
|
+
*
|
|
415
|
+
* React Native has no `navigator.credentials`, but both platforms do have
|
|
416
|
+
* passkey APIs - `ASAuthorization` on iOS, Credential Manager on Android - and
|
|
417
|
+
* the community libraries (`react-native-passkey`, `expo-passkeys`) speak the
|
|
418
|
+
* same WebAuthn JSON the server already emits. So the app supplies the ceremony
|
|
419
|
+
* and the SDK keeps the protocol: option decoding, response projection, and the
|
|
420
|
+
* in-flight de-duplication all come from `@authowl/core`.
|
|
421
|
+
*
|
|
422
|
+
* The adapter is the app's because the native libraries differ, need native
|
|
423
|
+
* builds, and require associated-domain configuration the SDK cannot do on the
|
|
424
|
+
* app's behalf.
|
|
425
|
+
*/
|
|
426
|
+
|
|
427
|
+
/** The platform passkey calls an app must provide. */
|
|
428
|
+
interface NativePasskeyAdapter {
|
|
429
|
+
/**
|
|
430
|
+
* Run the platform's registration ceremony.
|
|
431
|
+
*
|
|
432
|
+
* `optionsJSON` is the server's WebAuthn creation options; return the
|
|
433
|
+
* credential the platform produced. Throw to signal cancellation or failure.
|
|
434
|
+
*/
|
|
435
|
+
register(optionsJSON: unknown): Promise<PasskeyRegistrationResponse>;
|
|
436
|
+
/** Run the platform's authentication ceremony. */
|
|
437
|
+
authenticate(optionsJSON: unknown): Promise<PasskeyAuthenticationResponse>;
|
|
438
|
+
/**
|
|
439
|
+
* Optional: map a platform failure to a stable code.
|
|
440
|
+
*
|
|
441
|
+
* Without it a cancelled prompt is reported as a generic ceremony error. iOS
|
|
442
|
+
* and Android both surface cancellation distinctly, and users cancel far more
|
|
443
|
+
* often than anything actually breaks, so implementing this is worth it.
|
|
444
|
+
*/
|
|
445
|
+
errorCode?(error: unknown): string | undefined;
|
|
446
|
+
}
|
|
447
|
+
/**
|
|
448
|
+
* Adapt a platform passkey library into the factory `@authowl/core` expects.
|
|
449
|
+
*
|
|
450
|
+
* Pass the result as `passkeys` to `<AuthOwlProvider>`; without it the passkey
|
|
451
|
+
* ceremony is absent from the client's type entirely, so an app cannot call a
|
|
452
|
+
* prompt that would fail.
|
|
453
|
+
*/
|
|
454
|
+
declare function createNativePasskeys(adapter: NativePasskeyAdapter): PasskeyCeremonyClientFactory;
|
|
455
|
+
|
|
456
|
+
/** An ID token obtained from a provider's native SDK. */
|
|
457
|
+
interface ProviderIdToken {
|
|
458
|
+
token: string;
|
|
459
|
+
accessToken?: string;
|
|
460
|
+
nonce?: string;
|
|
461
|
+
}
|
|
462
|
+
interface SocialProvider {
|
|
463
|
+
/** The provider id AuthOwl knows, e.g. `google` or `apple`. */
|
|
464
|
+
id: string;
|
|
465
|
+
/** Display name, interpolated into the localized button label. */
|
|
466
|
+
label: string;
|
|
467
|
+
/**
|
|
468
|
+
* Run the provider's native sign-in and return its ID token.
|
|
469
|
+
*
|
|
470
|
+
* Return `null` when the user cancels. The app owns this because the native
|
|
471
|
+
* SDKs differ per provider and per platform, and bundling one would force
|
|
472
|
+
* every consumer to carry it - `google_sign_in`, `expo-apple-authentication`,
|
|
473
|
+
* and friends stay the app's dependency, not the SDK's.
|
|
474
|
+
*/
|
|
475
|
+
getIdToken: () => Promise<ProviderIdToken | null>;
|
|
476
|
+
}
|
|
477
|
+
interface SocialButtonsProps {
|
|
478
|
+
providers: readonly SocialProvider[];
|
|
479
|
+
onSignedIn?: () => void;
|
|
480
|
+
theme?: AuthOwlTheme;
|
|
481
|
+
}
|
|
482
|
+
/**
|
|
483
|
+
* One button per provider.
|
|
484
|
+
*
|
|
485
|
+
* Redirect OAuth is not an option here: it completes inside a system browser
|
|
486
|
+
* whose cookie jar this client cannot read, so the session would land somewhere
|
|
487
|
+
* the app can never see it. ID-token exchange is the only native flow that
|
|
488
|
+
* actually establishes a session.
|
|
489
|
+
*/
|
|
490
|
+
declare function SocialButtons({ providers, onSignedIn, theme, }: SocialButtonsProps): react.JSX.Element | null;
|
|
491
|
+
|
|
492
|
+
declare function useStyles(theme?: AuthOwlTheme): {
|
|
493
|
+
container: {
|
|
494
|
+
gap: number;
|
|
495
|
+
backgroundColor: string;
|
|
496
|
+
};
|
|
497
|
+
title: {
|
|
498
|
+
fontSize: number;
|
|
499
|
+
fontWeight: string;
|
|
500
|
+
color: string;
|
|
501
|
+
};
|
|
502
|
+
label: {
|
|
503
|
+
fontSize: number;
|
|
504
|
+
fontWeight: string;
|
|
505
|
+
color: string;
|
|
506
|
+
};
|
|
507
|
+
field: {
|
|
508
|
+
gap: number;
|
|
509
|
+
};
|
|
510
|
+
input: {
|
|
511
|
+
borderWidth: number;
|
|
512
|
+
borderColor: string;
|
|
513
|
+
borderRadius: number;
|
|
514
|
+
paddingHorizontal: number;
|
|
515
|
+
paddingVertical: number;
|
|
516
|
+
fontSize: number;
|
|
517
|
+
color: string;
|
|
518
|
+
backgroundColor: string;
|
|
519
|
+
};
|
|
520
|
+
inputInvalid: {
|
|
521
|
+
borderColor: string;
|
|
522
|
+
};
|
|
523
|
+
button: {
|
|
524
|
+
borderRadius: number;
|
|
525
|
+
paddingVertical: number;
|
|
526
|
+
alignItems: string;
|
|
527
|
+
backgroundColor: string;
|
|
528
|
+
};
|
|
529
|
+
buttonDisabled: {
|
|
530
|
+
opacity: number;
|
|
531
|
+
};
|
|
532
|
+
buttonText: {
|
|
533
|
+
color: string;
|
|
534
|
+
fontSize: number;
|
|
535
|
+
fontWeight: string;
|
|
536
|
+
};
|
|
537
|
+
link: {
|
|
538
|
+
color: string;
|
|
539
|
+
fontSize: number;
|
|
540
|
+
};
|
|
541
|
+
consentRow: {
|
|
542
|
+
flexDirection: string;
|
|
543
|
+
alignItems: string;
|
|
544
|
+
gap: number;
|
|
545
|
+
};
|
|
546
|
+
consentToggle: {
|
|
547
|
+
minWidth: number;
|
|
548
|
+
height: number;
|
|
549
|
+
alignItems: string;
|
|
550
|
+
justifyContent: string;
|
|
551
|
+
};
|
|
552
|
+
consentBox: {
|
|
553
|
+
width: number;
|
|
554
|
+
height: number;
|
|
555
|
+
alignItems: string;
|
|
556
|
+
justifyContent: string;
|
|
557
|
+
borderWidth: number;
|
|
558
|
+
borderColor: string;
|
|
559
|
+
borderRadius: number;
|
|
560
|
+
backgroundColor: string;
|
|
561
|
+
};
|
|
562
|
+
consentBoxChecked: {
|
|
563
|
+
borderColor: string;
|
|
564
|
+
backgroundColor: string;
|
|
565
|
+
};
|
|
566
|
+
consentBoxDisabled: {
|
|
567
|
+
opacity: number;
|
|
568
|
+
};
|
|
569
|
+
consentCheck: {
|
|
570
|
+
color: string;
|
|
571
|
+
fontSize: number;
|
|
572
|
+
fontWeight: string;
|
|
573
|
+
lineHeight: number;
|
|
574
|
+
};
|
|
575
|
+
consentText: {
|
|
576
|
+
flex: number;
|
|
577
|
+
color: string;
|
|
578
|
+
fontSize: number;
|
|
579
|
+
lineHeight: number;
|
|
580
|
+
};
|
|
581
|
+
consentLink: {
|
|
582
|
+
color: string;
|
|
583
|
+
textDecorationLine: string;
|
|
584
|
+
};
|
|
585
|
+
error: {
|
|
586
|
+
color: string;
|
|
587
|
+
fontSize: number;
|
|
588
|
+
};
|
|
589
|
+
};
|
|
590
|
+
interface FieldProps {
|
|
591
|
+
label: string;
|
|
592
|
+
value: string;
|
|
593
|
+
onChangeText: (value: string) => void;
|
|
594
|
+
theme?: AuthOwlTheme;
|
|
595
|
+
placeholder?: string;
|
|
596
|
+
secure?: boolean;
|
|
597
|
+
invalid?: boolean;
|
|
598
|
+
editable?: boolean;
|
|
599
|
+
testID?: string;
|
|
600
|
+
autoComplete?: string;
|
|
601
|
+
keyboardType?: string;
|
|
602
|
+
maxLength?: number;
|
|
603
|
+
onSubmitEditing?: () => void;
|
|
604
|
+
}
|
|
605
|
+
/** A labelled text input. */
|
|
606
|
+
declare function Field({ label, value, onChangeText, theme, placeholder, secure, invalid, editable, testID, autoComplete, keyboardType, maxLength, onSubmitEditing, }: FieldProps): react.JSX.Element;
|
|
607
|
+
interface SubmitButtonProps {
|
|
608
|
+
label: string;
|
|
609
|
+
busyLabel: string;
|
|
610
|
+
onPress: () => void;
|
|
611
|
+
busy?: boolean;
|
|
612
|
+
disabled?: boolean;
|
|
613
|
+
theme?: AuthOwlTheme;
|
|
614
|
+
testID?: string;
|
|
615
|
+
}
|
|
616
|
+
/** The primary action, with its own busy state. */
|
|
617
|
+
declare function SubmitButton({ label, busyLabel, onPress, busy, disabled, theme, testID, }: SubmitButtonProps): react.JSX.Element;
|
|
618
|
+
/**
|
|
619
|
+
* An error message.
|
|
620
|
+
*
|
|
621
|
+
* Announced politely so a screen reader reports a failed sign-in without
|
|
622
|
+
* interrupting whatever the user is doing.
|
|
623
|
+
*/
|
|
624
|
+
declare function FormError({ message, theme, testID, }: {
|
|
625
|
+
message: string | null;
|
|
626
|
+
theme?: AuthOwlTheme;
|
|
627
|
+
testID?: string;
|
|
628
|
+
}): react.JSX.Element | null;
|
|
629
|
+
|
|
630
|
+
/**
|
|
631
|
+
* Localization for the React Native components.
|
|
632
|
+
*
|
|
633
|
+
* Reads the SAME catalogs the web components use (`@authowl/core/i18n`). That
|
|
634
|
+
* is a hard rule, not a convenience: a second catalog is how an Arabic string
|
|
635
|
+
* silently stops matching between the web app and the phone app.
|
|
636
|
+
*/
|
|
637
|
+
|
|
638
|
+
/** Translate a catalog key in the active locale. */
|
|
639
|
+
declare function useT(): (key: MessageKey, params?: MessageParams) => string;
|
|
640
|
+
/** The active locale and its writing direction. */
|
|
641
|
+
declare function useLocale(): {
|
|
642
|
+
locale: Locale;
|
|
643
|
+
direction: 'ltr' | 'rtl';
|
|
644
|
+
};
|
|
645
|
+
/**
|
|
646
|
+
* Turn a server failure into a localized sentence.
|
|
647
|
+
*
|
|
648
|
+
* Falls back to the generic message rather than surfacing a raw server string:
|
|
649
|
+
* an untranslated backend error in the middle of an Arabic sign-in screen is
|
|
650
|
+
* both a leak and a UX failure.
|
|
651
|
+
*/
|
|
652
|
+
declare function useServerError(): (error: ServerErrorInput | null | undefined, fallback: MessageKey) => string;
|
|
653
|
+
|
|
654
|
+
export { type AuthOwlHeadlessNative, type AuthOwlNative, type AuthOwlNativeConfig, type AuthOwlNativeConfigWithPasskeys, type AuthOwlPasskeyNative, AuthOwlProvider, type AuthOwlProviderProps, type AuthOwlTheme, type CookieJarOptions, EmailOtpForm, type EmailOtpFormProps, Field, type FieldProps, FormError, MemoryStorage, type NativePasskeyAdapter, OrganizationSwitcher, type OrganizationSwitcherProps, PasskeyEnrollment, type PasskeyEnrollmentProps, PasskeySignInButton, type PasskeySignInButtonProps, type ProviderIdToken, type PublicConfigState, type SecureStorage, SignIn, type SignInProps, SignUp, type SignUpProps, SocialButtons, type SocialButtonsProps, type SocialProvider, SubmitButton, type SubmitButtonProps, type UseAuthResult, createAuthOwlNative, createCookieJarFetch, createNativePasskeys, createStyles, darkTheme, defaultTheme, readSetCookie, sessionStorageKey, signInWithSocialIdToken, useAuth, useAuthOwlClient, useAuthOwlLocale, useLocale, usePublicConfig, useServerError, useSession, useSocialSignIn, useStyles, useT, useUser };
|