@seamless-auth/react 0.4.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,21 +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
- verifyStepUpWithTotp(code: string): Promise<StepUpVerificationResult>;
125
- logout(): Promise<void>;
126
- logoutAllSessions(): Promise<void>;
127
- deleteUser(): Promise<void>;
128
- login(identifier: string, passkeyAvailable: boolean): Promise<Response>;
129
- handlePasskeyLogin(): Promise<boolean>;
130
- updateCredential(credential: Credential): Promise<Credential>;
131
- 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>>;
132
133
  }
133
134
  ```
134
135
 
@@ -160,12 +161,12 @@ If you are building a fully custom flow, call `markSignedIn()` after a successfu
160
161
  const { markSignedIn, refreshSession } = useAuth();
161
162
 
162
163
  async function completeLogin() {
163
- const response = await authClient.login({
164
+ const { error } = await authClient.login({
164
165
  identifier: 'user@example.com',
165
166
  passkeyAvailable: true,
166
167
  });
167
168
 
168
- if (response.ok) {
169
+ if (!error) {
169
170
  markSignedIn();
170
171
  await refreshSession();
171
172
  }
@@ -201,8 +202,8 @@ function DeleteAccountButton() {
201
202
  const { refreshStepUpStatus, verifyStepUpWithPasskey } = useAuth();
202
203
 
203
204
  async function handleDeleteAccount() {
204
- const status = await refreshStepUpStatus();
205
- const fresh = status?.fresh ? true : (await verifyStepUpWithPasskey()).success;
205
+ const { data: status } = await refreshStepUpStatus();
206
+ const fresh = status?.fresh ? true : !(await verifyStepUpWithPasskey()).error;
206
207
 
207
208
  if (!fresh) {
208
209
  return;
@@ -215,13 +216,13 @@ function DeleteAccountButton() {
215
216
  }
216
217
  ```
217
218
 
218
- 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`. Both verification helpers return a `StepUpVerificationResult` and refresh the provider's `stepUpStatus` on success.
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.
219
220
 
220
221
  ```tsx
221
222
  const { verifyStepUpWithTotp } = useAuth();
222
223
 
223
- const result = await verifyStepUpWithTotp('123456'); // 6-digit code from the user's authenticator app
224
- if (result.success) {
224
+ const { error } = await verifyStepUpWithTotp('123456'); // 6-digit code from the authenticator app
225
+ if (!error) {
225
226
  // step-up is fresh; proceed with the sensitive action
226
227
  }
227
228
  ```
@@ -237,16 +238,14 @@ import type { TotpStatus, TotpEnrollmentStartResult } from '@seamless-auth/react
237
238
  const authClient = createSeamlessAuthClient({ apiHost: 'https://your.api' });
238
239
 
239
240
  // 1. Check whether TOTP is already enabled
240
- const status: TotpStatus = await (await authClient.getTotpStatus()).json();
241
+ const { data: status } = await authClient.getTotpStatus();
241
242
 
242
243
  // 2. Start enrollment: render `otpauthUrl` as a QR code (or show `secret` for manual entry)
243
- const enrollment: TotpEnrollmentStartResult = await (
244
- await authClient.startTotpEnrollment()
245
- ).json();
244
+ const { data: enrollment } = await authClient.startTotpEnrollment();
246
245
 
247
246
  // 3. Confirm the first code from the user's authenticator app
248
- const verifyResponse = await authClient.verifyTotpEnrollment('123456');
249
- if (verifyResponse.ok) {
247
+ const { error } = await authClient.verifyTotpEnrollment('123456');
248
+ if (!error) {
250
249
  // TOTP is now enabled
251
250
  }
252
251
 
@@ -254,7 +253,7 @@ if (verifyResponse.ok) {
254
253
  await authClient.disableTotp('123456');
255
254
  ```
256
255
 
257
- `getTotpStatus`, `startTotpEnrollment`, `verifyTotpEnrollment`, and `disableTotp` return raw `Response` objects, so check `response.ok` and parse the body yourself. Enrolling TOTP is a sensitive change; gate it behind a fresh step-up when appropriate.
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.
258
257
 
259
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.
260
259
 
@@ -292,18 +291,18 @@ if (prfSupported) {
292
291
  For local key unwrap flows such as Seamless Secrets, use PRF during step-up and consume the returned bytes in browser memory:
293
292
 
294
293
  ```ts
295
- const result = await authClient.verifyStepUpWithPasskeyPrf({
294
+ const { data, error } = await authClient.verifyStepUpWithPasskeyPrf({
296
295
  salt: vaultSaltBase64url,
297
296
  credentialId,
298
297
  });
299
298
 
300
- if (!result.success || !result.prf) {
301
- throw new Error('PRF step-up failed');
299
+ if (error) {
300
+ throw error;
302
301
  }
303
302
 
304
303
  const vaultUnlockMaterial: { credentialId: string; output: Uint8Array } = {
305
- credentialId: result.credentialId!,
306
- output: result.prf.output,
304
+ credentialId: data.credentialId,
305
+ output: data.prf.output,
307
306
  };
308
307
  ```
309
308
 
@@ -419,14 +418,18 @@ const authClient = createSeamlessAuthClient({
419
418
  apiHost: 'https://your.api',
420
419
  });
421
420
 
422
- const response = await authClient.login({
421
+ const { data, error } = await authClient.login({
423
422
  identifier: 'user@example.com',
424
423
  passkeyAvailable: true,
425
424
  });
426
425
 
427
- if (response.ok) {
428
- // Continue your custom flow
426
+ if (error) {
427
+ // error.message, error.status, and error.body carry the server detail
428
+ return;
429
429
  }
430
+
431
+ // data is typed as LoginStartResult
432
+ console.log(data.loginMethods);
430
433
  ```
431
434
 
432
435
  The headless client exposes helpers for:
@@ -443,17 +446,40 @@ The headless client exposes helpers for:
443
446
  - logout and delete-user
444
447
  - credential update and deletion
445
448
 
446
- Client methods return raw `Response` objects except for the passkey and step-up 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.
476
+
477
+ `SeamlessAuthError` carries the server's `message`, the HTTP `status`, and the parsed response
478
+ `body`, so you can branch on a specific failure.
447
479
 
448
- - `loginWithPasskey(options?: PasskeyLoginOptions): Promise<PasskeyLoginWithPrfResult>`
449
- - `registerPasskey(metadata | { metadata, requestPrf?, requirePrf? }): Promise<PasskeyRegistrationResult>`
450
- - `isPasskeyPrfSupported(): Promise<boolean>`
451
- - `verifyStepUpWithPasskey(): Promise<StepUpVerificationResult>`
452
- - `verifyStepUpWithTotp(code): Promise<StepUpVerificationResult>`
453
- - `verifyStepUpWithPasskeyPrf(input): Promise<StepUpWithPasskeyPrfResult>`
454
- - `listOAuthProviders(): Promise<OAuthProvidersResult>`
455
- - `startOAuthLogin(input): Promise<StartOAuthLoginResult>`
456
- - `finishOAuthLogin(input): Promise<Response>`
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.
457
483
 
458
484
  ## React Hooks For Custom UI
459
485
 
@@ -468,12 +494,12 @@ function CustomLogin() {
468
494
  const { passkeySupported, loading } = usePasskeySupport();
469
495
 
470
496
  async function handleEmailLogin() {
471
- const response = await authClient.login({
497
+ const { error } = await authClient.login({
472
498
  identifier: 'user@example.com',
473
499
  passkeyAvailable: passkeySupported,
474
500
  });
475
501
 
476
- if (response.ok) {
502
+ if (!error) {
477
503
  await refreshSession();
478
504
  }
479
505
  }
@@ -486,21 +512,260 @@ function CustomLogin() {
486
512
  }
487
513
  ```
488
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
+
489
733
  ## Built-In Routes
490
734
 
491
- `AuthRoutes` currently includes:
735
+ `AuthRoutes` serves these canonical paths:
492
736
 
493
737
  - `/login`
494
- - `/passKeyLogin`
495
- - `/verifyPhoneOTP`
496
- - `/verifyEmailOTP`
497
- - `/verify-magiclink`
738
+ - `/passkey-login`
739
+ - `/verify-phone-otp`
740
+ - `/verify-email-otp`
741
+ - `/verify-magic-link`
498
742
  - `/oauth/callback`
499
- - `/registerPasskey`
500
- - `/magiclinks-sent`
743
+ - `/register-passkey`
744
+ - `/magic-link-sent`
501
745
 
502
746
  These are optional UI wrappers over the same SDK primitives the package now exports for custom flows.
503
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
+
504
769
  ## Backend Expectations
505
770
 
506
771
  This package assumes a Seamless Auth-compatible backend with the auth adapter mounted at `/auth`.
@@ -520,15 +785,15 @@ The built-in flows assume compatible endpoints for:
520
785
  - `/webAuthn/login/finish`
521
786
  - `/webAuthn/register/start`
522
787
  - `/webAuthn/register/finish`
523
- - `/otp/generate-phone-otp`
524
- - `/otp/generate-email-otp`
788
+ - `POST /otp/generate-phone-otp`
789
+ - `POST /otp/generate-email-otp`
525
790
  - `/otp/verify-phone-otp`
526
791
  - `/otp/verify-email-otp`
527
- - `/otp/generate-login-phone-otp`
528
- - `/otp/generate-login-email-otp`
792
+ - `POST /otp/generate-login-phone-otp`
793
+ - `POST /otp/generate-login-email-otp`
529
794
  - `/otp/verify-login-phone-otp`
530
795
  - `/otp/verify-login-email-otp`
531
- - `/magic-link`
796
+ - `POST /magic-link`
532
797
  - `/magic-link/check`
533
798
  - `/magic-link/verify/:token`
534
799
  - `/oauth/providers`
@@ -551,6 +816,11 @@ The built-in flows assume compatible endpoints for:
551
816
  - `/organizations/:organizationId/members`
552
817
  - `/organizations/:organizationId/members/:userId`
553
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.
823
+
554
824
  ## Notes
555
825
 
556
826
  - This package does not create its own `<BrowserRouter>`.
@@ -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,19 +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>;
32
- verifyStepUpWithTotp: (code: string) => Promise<StepUpVerificationResult>;
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>>;
33
34
  loading: boolean;
34
35
  }
35
36
  /**