@seamless-auth/react 0.3.0 → 0.5.0

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 CHANGED
@@ -17,7 +17,8 @@
17
17
  - `useAuthClient()`
18
18
  - `usePasskeySupport()`
19
19
  - `hasScopedRole()` and `roleGrantsAccess()`
20
- - types including `AuthContextType`, `Credential`, `User`, `OAuthProvider`, `StepUpStatus`, and the headless client input/result types
20
+ - `SeamlessAuthError`, the error type carried on a failed result
21
+ - types including `AuthContextType`, `Credential`, `User`, `OAuthProvider`, `StepUpStatus`, the `SeamlessAuthResult` wrapper, and the headless client input/result types
21
22
 
22
23
  ## Installation
23
24
 
@@ -114,20 +115,21 @@ You are still responsible for your app’s route protection and redirects.
114
115
  markSignedIn(): void;
115
116
  hasRole(role: string): boolean | undefined;
116
117
  hasScopedRole(role: string | string[]): boolean | undefined;
117
- listOAuthProviders(): Promise<OAuthProvidersResult>;
118
- startOAuthLogin(input: StartOAuthLoginInput): Promise<StartOAuthLoginResult>;
119
- finishOAuthLogin(input: FinishOAuthLoginInput): Promise<void>;
120
- refreshSession(): Promise<void>;
121
- refreshStepUpStatus(): Promise<StepUpStatus | null>;
122
- verifyStepUpWithPasskey(): Promise<StepUpVerificationResult>;
123
- verifyStepUpWithPasskeyPrf(input: PasskeyPrfInput): Promise<StepUpWithPasskeyPrfResult>;
124
- logout(): Promise<void>;
125
- logoutAllSessions(): Promise<void>;
126
- deleteUser(): Promise<void>;
127
- login(identifier: string, passkeyAvailable: boolean): Promise<Response>;
128
- handlePasskeyLogin(): Promise<boolean>;
129
- updateCredential(credential: Credential): Promise<Credential>;
130
- deleteCredential(credentialId: string): Promise<void>;
118
+ listOAuthProviders(): Promise<SeamlessAuthResult<OAuthProvidersResult>>;
119
+ startOAuthLogin(input: StartOAuthLoginInput): Promise<SeamlessAuthResult<StartOAuthLoginResult>>;
120
+ finishOAuthLogin(input: FinishOAuthLoginInput): Promise<SeamlessAuthResult<MessageResult>>;
121
+ refreshSession(): Promise<SeamlessAuthResult<CurrentUserResult>>;
122
+ refreshStepUpStatus(): Promise<SeamlessAuthResult<StepUpStatus>>;
123
+ verifyStepUpWithPasskey(): Promise<SeamlessAuthResult<StepUpStatus>>;
124
+ verifyStepUpWithPasskeyPrf(input: PasskeyPrfInput): Promise<SeamlessAuthResult<StepUpPrfData>>;
125
+ verifyStepUpWithTotp(code: string): Promise<SeamlessAuthResult<StepUpStatus>>;
126
+ logout(): Promise<SeamlessAuthResult<MessageResult>>;
127
+ logoutAllSessions(): Promise<SeamlessAuthResult<MessageResult>>;
128
+ deleteUser(): Promise<SeamlessAuthResult<MessageResult>>;
129
+ login(identifier: string, passkeyAvailable: boolean): Promise<SeamlessAuthResult<LoginStartResult>>;
130
+ handlePasskeyLogin(): Promise<SeamlessAuthResult<PasskeyLoginData>>;
131
+ updateCredential(credential: Credential): Promise<SeamlessAuthResult<Credential>>;
132
+ deleteCredential(credentialId: string): Promise<SeamlessAuthResult<MessageResult>>;
131
133
  }
132
134
  ```
133
135
 
@@ -159,12 +161,12 @@ If you are building a fully custom flow, call `markSignedIn()` after a successfu
159
161
  const { markSignedIn, refreshSession } = useAuth();
160
162
 
161
163
  async function completeLogin() {
162
- const response = await authClient.login({
164
+ const { error } = await authClient.login({
163
165
  identifier: 'user@example.com',
164
166
  passkeyAvailable: true,
165
167
  });
166
168
 
167
- if (response.ok) {
169
+ if (!error) {
168
170
  markSignedIn();
169
171
  await refreshSession();
170
172
  }
@@ -200,8 +202,8 @@ function DeleteAccountButton() {
200
202
  const { refreshStepUpStatus, verifyStepUpWithPasskey } = useAuth();
201
203
 
202
204
  async function handleDeleteAccount() {
203
- const status = await refreshStepUpStatus();
204
- const fresh = status?.fresh ? true : (await verifyStepUpWithPasskey()).success;
205
+ const { data: status } = await refreshStepUpStatus();
206
+ const fresh = status?.fresh ? true : !(await verifyStepUpWithPasskey()).error;
205
207
 
206
208
  if (!fresh) {
207
209
  return;
@@ -214,7 +216,46 @@ function DeleteAccountButton() {
214
216
  }
215
217
  ```
216
218
 
217
- The current step-up backend supports WebAuthn/passkeys. `refreshStepUpStatus()` calls `/step-up/status`, and `verifyStepUpWithPasskey()` performs the `/step-up/webauthn/start` and `/step-up/webauthn/finish` challenge flow.
219
+ Step-up supports WebAuthn/passkeys and TOTP (authenticator apps). `refreshStepUpStatus()` calls `/step-up/status`, `verifyStepUpWithPasskey()` performs the `/step-up/webauthn/start` and `/step-up/webauthn/finish` challenge flow, and `verifyStepUpWithTotp(code)` verifies a 6-digit authenticator code via `/totp/verify-mfa`. The verification helpers return a `SeamlessAuthResult<StepUpStatus>` and refresh the provider's `stepUpStatus` when they succeed.
220
+
221
+ ```tsx
222
+ const { verifyStepUpWithTotp } = useAuth();
223
+
224
+ const { error } = await verifyStepUpWithTotp('123456'); // 6-digit code from the authenticator app
225
+ if (!error) {
226
+ // step-up is fresh; proceed with the sensitive action
227
+ }
228
+ ```
229
+
230
+ ### TOTP (authenticator apps)
231
+
232
+ TOTP lets users register an authenticator app (Google Authenticator, 1Password, etc.) as a second factor for step-up verification. The SDK exposes headless client methods for enrollment and management; use them from a settings screen. All require an authenticated session.
233
+
234
+ ```ts
235
+ import { createSeamlessAuthClient } from '@seamless-auth/react';
236
+ import type { TotpStatus, TotpEnrollmentStartResult } from '@seamless-auth/react';
237
+
238
+ const authClient = createSeamlessAuthClient({ apiHost: 'https://your.api' });
239
+
240
+ // 1. Check whether TOTP is already enabled
241
+ const { data: status } = await authClient.getTotpStatus();
242
+
243
+ // 2. Start enrollment: render `otpauthUrl` as a QR code (or show `secret` for manual entry)
244
+ const { data: enrollment } = await authClient.startTotpEnrollment();
245
+
246
+ // 3. Confirm the first code from the user's authenticator app
247
+ const { error } = await authClient.verifyTotpEnrollment('123456');
248
+ if (!error) {
249
+ // TOTP is now enabled
250
+ }
251
+
252
+ // Disabling requires a current code
253
+ await authClient.disableTotp('123456');
254
+ ```
255
+
256
+ These methods follow the standard result convention: check `error`, then read `data`. Enrolling TOTP is a sensitive change; gate it behind a fresh step-up when appropriate.
257
+
258
+ > TOTP is not currently a login second factor. The Seamless Auth API issues a full session on the first factor and does not gate login on TOTP, so TOTP applies to step-up verification, not to the login flow.
218
259
 
219
260
  ### WebAuthn PRF
220
261
 
@@ -250,18 +291,18 @@ if (prfSupported) {
250
291
  For local key unwrap flows such as Seamless Secrets, use PRF during step-up and consume the returned bytes in browser memory:
251
292
 
252
293
  ```ts
253
- const result = await authClient.verifyStepUpWithPasskeyPrf({
294
+ const { data, error } = await authClient.verifyStepUpWithPasskeyPrf({
254
295
  salt: vaultSaltBase64url,
255
296
  credentialId,
256
297
  });
257
298
 
258
- if (!result.success || !result.prf) {
259
- throw new Error('PRF step-up failed');
299
+ if (error) {
300
+ throw error;
260
301
  }
261
302
 
262
303
  const vaultUnlockMaterial: { credentialId: string; output: Uint8Array } = {
263
- credentialId: result.credentialId!,
264
- output: result.prf.output,
304
+ credentialId: data.credentialId,
305
+ output: data.prf.output,
265
306
  };
266
307
  ```
267
308
 
@@ -323,11 +364,14 @@ function OAuthCallback() {
323
364
 
324
365
  useEffect(() => {
325
366
  const params = new URLSearchParams(window.location.search);
326
- const providerId = 'google';
367
+ // Persist the provider you passed to startOAuthLogin so the callback knows
368
+ // which provider to finish. The built-in AuthRoutes flow stores this in
369
+ // sessionStorage; use whatever your custom start flow saved.
370
+ const providerId = sessionStorage.getItem('seamless:oauth:provider');
327
371
  const code = params.get('code');
328
372
  const state = params.get('state');
329
373
 
330
- if (!code || !state) {
374
+ if (!providerId || !code || !state) {
331
375
  return;
332
376
  }
333
377
 
@@ -374,14 +418,18 @@ const authClient = createSeamlessAuthClient({
374
418
  apiHost: 'https://your.api',
375
419
  });
376
420
 
377
- const response = await authClient.login({
421
+ const { data, error } = await authClient.login({
378
422
  identifier: 'user@example.com',
379
423
  passkeyAvailable: true,
380
424
  });
381
425
 
382
- if (response.ok) {
383
- // Continue your custom flow
426
+ if (error) {
427
+ // error.message, error.status, and error.body carry the server detail
428
+ return;
384
429
  }
430
+
431
+ // data is typed as LoginStartResult
432
+ console.log(data.loginMethods);
385
433
  ```
386
434
 
387
435
  The headless client exposes helpers for:
@@ -393,20 +441,45 @@ The headless client exposes helpers for:
393
441
  - magic-link request, verify, and polling
394
442
  - OAuth provider listing, start, and callback completion
395
443
  - passkey registration
396
- - step-up status and passkey verification
444
+ - step-up status, passkey verification, and TOTP verification
445
+ - TOTP enrollment, status, and disable
397
446
  - logout and delete-user
398
447
  - credential update and deletion
399
448
 
400
- Client methods return raw `Response` objects except for the passkey convenience helpers:
449
+ ### Result convention
450
+
451
+ Every request method resolves to a `SeamlessAuthResult<T>`:
452
+
453
+ ```ts
454
+ type SeamlessAuthResult<T> =
455
+ | { data: T; error: null }
456
+ | { data: null; error: SeamlessAuthError };
457
+ ```
458
+
459
+ Check `error` first, then read `data`. TypeScript enforces this: `data` is not readable until the
460
+ error has been ruled out.
461
+
462
+ ```ts
463
+ const { data, error } = await authClient.getCurrentUser();
464
+
465
+ if (error) {
466
+ console.log(error.message, error.status, error.body);
467
+ return;
468
+ }
469
+
470
+ setUser(data.user); // typed as CurrentUserResult
471
+ ```
472
+
473
+ Nothing throws for an HTTP failure, and transport failures are absorbed too, reported as an error
474
+ with `status` `0`. That means an expected auth outcome such as a wrong OTP, an expired magic link, or
475
+ a disabled provider is a value you can map straight to UI state rather than an exception to catch.
401
476
 
402
- - `loginWithPasskey(options?: PasskeyLoginOptions): Promise<PasskeyLoginWithPrfResult>`
403
- - `registerPasskey(metadata | { metadata, requestPrf?, requirePrf? }): Promise<PasskeyRegistrationResult>`
404
- - `isPasskeyPrfSupported(): Promise<boolean>`
405
- - `verifyStepUpWithPasskey(): Promise<StepUpVerificationResult>`
406
- - `verifyStepUpWithPasskeyPrf(input): Promise<StepUpWithPasskeyPrfResult>`
407
- - `listOAuthProviders(): Promise<OAuthProvidersResult>`
408
- - `startOAuthLogin(input): Promise<StartOAuthLoginResult>`
409
- - `finishOAuthLogin(input): Promise<Response>`
477
+ `SeamlessAuthError` carries the server's `message`, the HTTP `status`, and the parsed response
478
+ `body`, so you can branch on a specific failure.
479
+
480
+ The single exception is `isPasskeySupported`-style capability checks:
481
+ `isPasskeyPrfSupported(): Promise<boolean>` is a local check rather than a request, so it returns a
482
+ plain boolean.
410
483
 
411
484
  ## React Hooks For Custom UI
412
485
 
@@ -421,12 +494,12 @@ function CustomLogin() {
421
494
  const { passkeySupported, loading } = usePasskeySupport();
422
495
 
423
496
  async function handleEmailLogin() {
424
- const response = await authClient.login({
497
+ const { error } = await authClient.login({
425
498
  identifier: 'user@example.com',
426
499
  passkeyAvailable: passkeySupported,
427
500
  });
428
501
 
429
- if (response.ok) {
502
+ if (!error) {
430
503
  await refreshSession();
431
504
  }
432
505
  }
@@ -439,20 +512,260 @@ function CustomLogin() {
439
512
  }
440
513
  ```
441
514
 
515
+ ### One error style everywhere
516
+
517
+ `useAuth()` helpers and the headless client report failure the same way: both return
518
+ `{ data, error }` and neither throws. Whatever surface you reach for, the handling is identical.
519
+
520
+ ```tsx
521
+ const { error } = await updateCredential({ ...credential, friendlyName: 'Work laptop' });
522
+
523
+ if (error) {
524
+ setMessage(error.message);
525
+ }
526
+ ```
527
+
528
+ Helpers that also mutate provider state, such as `switchOrganization` and `deleteCredential`, apply
529
+ that state change only when the call succeeds, then hand the result back for you to inspect.
530
+
531
+ ## Custom UI Recipes
532
+
533
+ Worked examples for the flows the bundled screens cover, using only public primitives.
534
+
535
+ ### Custom registration
536
+
537
+ Registration is two steps: create the account, then verify the emailed code. Call `markSignedIn()`
538
+ once the account is live so returning visits can default to sign-in.
539
+
540
+ ```tsx
541
+ import { useAuth, useAuthClient } from '@seamless-auth/react';
542
+ import { useState } from 'react';
543
+
544
+ function CustomRegistration() {
545
+ const { markSignedIn, refreshSession } = useAuth();
546
+ const authClient = useAuthClient();
547
+ const [step, setStep] = useState<'details' | 'verify'>('details');
548
+ const [message, setMessage] = useState('');
549
+
550
+ async function createAccount(email: string) {
551
+ // Registration needs only an email. A phone can be added and verified later.
552
+ const { error } = await authClient.register({ email });
553
+
554
+ if (error) {
555
+ setMessage(error.message);
556
+ return;
557
+ }
558
+
559
+ // The API emails a verification code as part of registering.
560
+ setStep('verify');
561
+ }
562
+
563
+ async function verifyCode(code: string) {
564
+ const { error } = await authClient.verifyEmailOtp(code);
565
+
566
+ if (error) {
567
+ setMessage(error.message);
568
+ return;
569
+ }
570
+
571
+ markSignedIn();
572
+ await refreshSession();
573
+ }
574
+
575
+ return step === 'details' ? (
576
+ <DetailsForm onSubmit={createAccount} error={message} />
577
+ ) : (
578
+ <CodeForm
579
+ onSubmit={verifyCode}
580
+ onResend={() => authClient.requestEmailOtp()}
581
+ error={message}
582
+ />
583
+ );
584
+ }
585
+ ```
586
+
587
+ To offer a passkey right after registering, call `registerPasskey()` before `refreshSession()`:
588
+
589
+ ```ts
590
+ const { data, error } = await authClient.registerPasskey({
591
+ friendlyName: 'My laptop',
592
+ platform: 'macOS',
593
+ browser: 'Chrome',
594
+ deviceInfo: navigator.userAgent,
595
+ });
596
+
597
+ if (!error) {
598
+ console.log(data.credentialId, data.prfCapable);
599
+ }
600
+ ```
601
+
602
+ ### OTP and magic-link continuation
603
+
604
+ > **The request helpers take no identifier.** `requestMagicLink()`, `requestLoginEmailOtp()`, and
605
+ > `requestLoginPhoneOtp()` send nothing but the session cookie. They rely on server-side state
606
+ > established by a preceding `login()` call, so calling them without it fails or targets the wrong
607
+ > account. This is not obvious from their signatures. Always call `login()` first, and use the same
608
+ > browser session for the continuation step.
609
+
610
+ ```tsx
611
+ function CustomLoginContinuation() {
612
+ const { login, refreshSession } = useAuth();
613
+ const authClient = useAuthClient();
614
+
615
+ async function start(identifier: string) {
616
+ // Required first: this is what the request helpers below depend on.
617
+ const { data, error } = await login(identifier, false);
618
+
619
+ if (error) {
620
+ return;
621
+ }
622
+
623
+ // Offer only what the server says this account supports.
624
+ return data.loginMethods ?? ['magic_link', 'email_otp'];
625
+ }
626
+
627
+ async function sendEmailCode() {
628
+ const { error } = await authClient.requestLoginEmailOtp();
629
+ if (error) {
630
+ // surface error.message
631
+ }
632
+ }
633
+
634
+ async function submitEmailCode(code: string) {
635
+ const { error } = await authClient.verifyLoginEmailOtp(code);
636
+
637
+ if (!error) {
638
+ await refreshSession();
639
+ }
640
+ }
641
+ }
642
+ ```
643
+
644
+ Magic links complete in whichever tab opens the emailed link, so a custom flow needs two pieces.
645
+
646
+ The waiting screen polls until the link is used:
647
+
648
+ ```ts
649
+ const interval = setInterval(async () => {
650
+ const { error } = await authClient.checkMagicLink();
651
+
652
+ if (!error) {
653
+ clearInterval(interval);
654
+ await refreshSession();
655
+ }
656
+ }, 5000);
657
+ ```
658
+
659
+ The landing route verifies the token from the query string, then refreshes its own session:
660
+
661
+ ```tsx
662
+ function CustomMagicLinkLanding() {
663
+ const { refreshSession } = useAuth(); // plus: import { useEffect } from 'react'
664
+ const authClient = useAuthClient();
665
+
666
+ useEffect(() => {
667
+ const token = new URLSearchParams(window.location.search).get('token');
668
+ if (!token) return;
669
+
670
+ void authClient.verifyMagicLink(token).then(async ({ error }) => {
671
+ if (!error) {
672
+ // Refresh here too. This tab set the cookie, but its provider state
673
+ // was loaded before the cookie existed.
674
+ await refreshSession();
675
+ }
676
+ });
677
+ }, [authClient, refreshSession]);
678
+
679
+ return <p>Finishing sign-in...</p>;
680
+ }
681
+ ```
682
+
683
+ The auth API emails a link pointing at `/verify-magiclink?token=...`, so a custom app must serve that
684
+ path.
685
+
686
+ ### Credential management
687
+
688
+ `useAuth()` exposes the signed-in user's passkeys plus helpers to rename and remove them. These
689
+ helpers update provider state on success and report failure through `error`.
690
+
691
+ ```tsx
692
+ import { useAuth } from '@seamless-auth/react';
693
+ import type { Credential } from '@seamless-auth/react';
694
+ import { useState } from 'react';
695
+
696
+ function PasskeyList() {
697
+ const { credentials, updateCredential, deleteCredential } = useAuth();
698
+ const [message, setMessage] = useState('');
699
+
700
+ async function rename(credential: Credential, friendlyName: string) {
701
+ const { error } = await updateCredential({ ...credential, friendlyName });
702
+
703
+ if (error) {
704
+ setMessage(error.message);
705
+ }
706
+ }
707
+
708
+ async function remove(credentialId: string) {
709
+ const { error } = await deleteCredential(credentialId);
710
+
711
+ if (error) {
712
+ setMessage(error.message);
713
+ }
714
+ }
715
+
716
+ return (
717
+ <ul>
718
+ {credentials.map(credential => (
719
+ <li key={credential.id}>
720
+ {credential.friendlyName ?? credential.deviceInfo}
721
+ <button onClick={() => void rename(credential, 'Work laptop')}>Rename</button>
722
+ <button onClick={() => void remove(credential.id)}>Remove</button>
723
+ </li>
724
+ ))}
725
+ </ul>
726
+ );
727
+ }
728
+ ```
729
+
730
+ Removing a passkey is a sensitive change. Gate it behind a fresh step-up when the account has other
731
+ factors, using `refreshStepUpStatus()` and `verifyStepUpWithPasskey()` from the step-up section.
732
+
442
733
  ## Built-In Routes
443
734
 
444
- `AuthRoutes` currently includes:
735
+ `AuthRoutes` serves these canonical paths:
445
736
 
446
737
  - `/login`
447
- - `/passKeyLogin`
448
- - `/verifyPhoneOTP`
449
- - `/verifyEmailOTP`
450
- - `/verify-magiclink`
451
- - `/registerPasskey`
452
- - `/magiclinks-sent`
738
+ - `/passkey-login`
739
+ - `/verify-phone-otp`
740
+ - `/verify-email-otp`
741
+ - `/verify-magic-link`
742
+ - `/oauth/callback`
743
+ - `/register-passkey`
744
+ - `/magic-link-sent`
453
745
 
454
746
  These are optional UI wrappers over the same SDK primitives the package now exports for custom flows.
455
747
 
748
+ ### Renamed routes
749
+
750
+ The earlier mixed-case paths were renamed and are no longer served. Anything linking directly to
751
+ them now falls through to `/login`, so update those links:
752
+
753
+ | Old path | New path |
754
+ | ------------------ | ------------------- |
755
+ | `/passKeyLogin` | `/passkey-login` |
756
+ | `/verifyPhoneOTP` | `/verify-phone-otp` |
757
+ | `/verifyEmailOTP` | `/verify-email-otp` |
758
+ | `/registerPasskey` | `/register-passkey` |
759
+ | `/magiclinks-sent` | `/magic-link-sent` |
760
+
761
+ Two paths are unchanged because they are owned by contracts outside this package:
762
+
763
+ - `/verify-magiclink` is the URL the auth API builds when it emails a magic link, so it has to match
764
+ that value exactly. Renaming it here would send every emailed link to `/login` with the token
765
+ discarded.
766
+ - `/oauth/callback` is registered with OAuth providers as an allowed redirect URI, so renaming it
767
+ would break configured integrations.
768
+
456
769
  ## Backend Expectations
457
770
 
458
771
  This package assumes a Seamless Auth-compatible backend with the auth adapter mounted at `/auth`.
@@ -472,11 +785,15 @@ The built-in flows assume compatible endpoints for:
472
785
  - `/webAuthn/login/finish`
473
786
  - `/webAuthn/register/start`
474
787
  - `/webAuthn/register/finish`
475
- - `/otp/generate-phone-otp`
476
- - `/otp/generate-email-otp`
788
+ - `POST /otp/generate-phone-otp`
789
+ - `POST /otp/generate-email-otp`
477
790
  - `/otp/verify-phone-otp`
478
791
  - `/otp/verify-email-otp`
479
- - `/magic-link`
792
+ - `POST /otp/generate-login-phone-otp`
793
+ - `POST /otp/generate-login-email-otp`
794
+ - `/otp/verify-login-phone-otp`
795
+ - `/otp/verify-login-email-otp`
796
+ - `POST /magic-link`
480
797
  - `/magic-link/check`
481
798
  - `/magic-link/verify/:token`
482
799
  - `/oauth/providers`
@@ -485,9 +802,24 @@ The built-in flows assume compatible endpoints for:
485
802
  - `/step-up/status`
486
803
  - `/step-up/webauthn/start`
487
804
  - `/step-up/webauthn/finish`
805
+ - `/totp/status`
806
+ - `/totp/enroll/start`
807
+ - `/totp/enroll/verify`
808
+ - `/totp/disable`
809
+ - `/totp/verify-mfa`
488
810
  - `/users/me`
489
811
  - `/users/credentials`
490
812
  - `/users/delete`
813
+ - `/organizations`
814
+ - `/organizations/:organizationId`
815
+ - `/organizations/:organizationId/switch`
816
+ - `/organizations/:organizationId/members`
817
+ - `/organizations/:organizationId/members/:userId`
818
+
819
+ The state-changing OTP and magic-link request routes are `POST` (marked above). They were previously
820
+ `GET`, which made them reachable as simple cross-site requests, so an `<img>` tag could trigger SMS or
821
+ email sends to a signed-in user. Using `@seamless-auth/react` with an older adapter that only serves the
822
+ `GET` forms returns a 404 for those requests. See the changelog for the minimum adapter version.
491
823
 
492
824
  ## Notes
493
825
 
@@ -1,13 +1,14 @@
1
- import { FinishOAuthLoginInput, OAuthProvidersResult, StartOAuthLoginInput, StartOAuthLoginResult, StepUpWithPasskeyPrfResult, StepUpStatus, StepUpVerificationResult } from '@/client/createSeamlessAuthClient';
2
- import { PasskeyPrfInput } from '@/client/webauthnPrf';
3
- import { Credential, Organization, User } from '@/types';
1
+ import { CurrentUserResult, FinishOAuthLoginInput, LoginStartResult, MessageResult, OAuthProvidersResult, OrganizationSwitchResult, PasskeyLoginData, StartOAuthLoginInput, StartOAuthLoginResult, StepUpPrfData, StepUpStatus } from './client/createSeamlessAuthClient';
2
+ import type { SeamlessAuthResult } from './client/result';
3
+ import { PasskeyPrfInput } from './client/webauthnPrf';
4
+ import { Credential, Organization, User } from './types';
4
5
  import React, { ReactNode } from 'react';
5
6
  export interface AuthContextType {
6
7
  user: User | null;
7
- logout: () => Promise<void>;
8
- logoutAllSessions: () => Promise<void>;
9
- deleteUser: () => Promise<void>;
10
- refreshSession: () => Promise<void>;
8
+ logout: () => Promise<SeamlessAuthResult<MessageResult>>;
9
+ logoutAllSessions: () => Promise<SeamlessAuthResult<MessageResult>>;
10
+ deleteUser: () => Promise<SeamlessAuthResult<MessageResult>>;
11
+ refreshSession: () => Promise<SeamlessAuthResult<CurrentUserResult>>;
11
12
  isAuthenticated: boolean;
12
13
  hasRole: (role: string) => boolean | undefined;
13
14
  hasScopedRole: (role: string | string[]) => boolean | undefined;
@@ -17,18 +18,19 @@ export interface AuthContextType {
17
18
  credentials: Credential[];
18
19
  organizations: Organization[];
19
20
  activeOrganization: Organization | null;
20
- switchOrganization: (organizationId: string) => Promise<void>;
21
- listOAuthProviders: () => Promise<OAuthProvidersResult>;
22
- startOAuthLogin: (input: StartOAuthLoginInput) => Promise<StartOAuthLoginResult>;
23
- finishOAuthLogin: (input: FinishOAuthLoginInput) => Promise<void>;
21
+ switchOrganization: (organizationId: string) => Promise<SeamlessAuthResult<OrganizationSwitchResult>>;
22
+ listOAuthProviders: () => Promise<SeamlessAuthResult<OAuthProvidersResult>>;
23
+ startOAuthLogin: (input: StartOAuthLoginInput) => Promise<SeamlessAuthResult<StartOAuthLoginResult>>;
24
+ finishOAuthLogin: (input: FinishOAuthLoginInput) => Promise<SeamlessAuthResult<MessageResult>>;
24
25
  stepUpStatus: StepUpStatus | null;
25
- updateCredential: (credential: Credential) => Promise<Credential>;
26
- deleteCredential: (credentialId: string) => Promise<void>;
27
- login: (identifier: string, passkeyAvailable: boolean) => Promise<Response | null>;
28
- handlePasskeyLogin: () => Promise<boolean>;
29
- refreshStepUpStatus: () => Promise<StepUpStatus | null>;
30
- verifyStepUpWithPasskey: () => Promise<StepUpVerificationResult>;
31
- verifyStepUpWithPasskeyPrf: (input: PasskeyPrfInput) => Promise<StepUpWithPasskeyPrfResult>;
26
+ updateCredential: (credential: Credential) => Promise<SeamlessAuthResult<Credential>>;
27
+ deleteCredential: (credentialId: string) => Promise<SeamlessAuthResult<MessageResult>>;
28
+ login: (identifier: string, passkeyAvailable: boolean) => Promise<SeamlessAuthResult<LoginStartResult>>;
29
+ handlePasskeyLogin: () => Promise<SeamlessAuthResult<PasskeyLoginData>>;
30
+ refreshStepUpStatus: () => Promise<SeamlessAuthResult<StepUpStatus>>;
31
+ verifyStepUpWithPasskey: () => Promise<SeamlessAuthResult<StepUpStatus>>;
32
+ verifyStepUpWithPasskeyPrf: (input: PasskeyPrfInput) => Promise<SeamlessAuthResult<StepUpPrfData>>;
33
+ verifyStepUpWithTotp: (code: string) => Promise<SeamlessAuthResult<StepUpStatus>>;
32
34
  loading: boolean;
33
35
  }
34
36
  /**