react-native-nitro-auth 0.5.12 → 0.6.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.
Files changed (92) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/README.md +88 -13
  3. package/android/build.gradle +4 -4
  4. package/android/gradle.properties +2 -2
  5. package/android/src/main/cpp/PlatformAuth+Android.cpp +87 -4
  6. package/android/src/main/java/com/auth/AuthAdapter.kt +85 -48
  7. package/android/src/main/java/com/auth/GoogleSignInActivity.kt +12 -2
  8. package/cpp/HybridAuth.cpp +168 -18
  9. package/cpp/HybridAuth.hpp +7 -0
  10. package/cpp/PlatformAuth.hpp +1 -0
  11. package/ios/AuthAdapter.swift +98 -24
  12. package/ios/PlatformAuth+iOS.mm +37 -1
  13. package/lib/commonjs/Auth.web.js +74 -21
  14. package/lib/commonjs/Auth.web.js.map +1 -1
  15. package/lib/commonjs/create-auth-service.js +10 -0
  16. package/lib/commonjs/create-auth-service.js.map +1 -1
  17. package/lib/commonjs/index.js +12 -0
  18. package/lib/commonjs/index.js.map +1 -1
  19. package/lib/commonjs/index.web.js +12 -0
  20. package/lib/commonjs/index.web.js.map +1 -1
  21. package/lib/commonjs/provider-options.js +6 -0
  22. package/lib/commonjs/provider-options.js.map +1 -0
  23. package/lib/commonjs/service.js.map +1 -1
  24. package/lib/commonjs/service.web.js.map +1 -1
  25. package/lib/commonjs/use-auth.js +21 -1
  26. package/lib/commonjs/use-auth.js.map +1 -1
  27. package/lib/module/Auth.web.js +74 -21
  28. package/lib/module/Auth.web.js.map +1 -1
  29. package/lib/module/create-auth-service.js +10 -0
  30. package/lib/module/create-auth-service.js.map +1 -1
  31. package/lib/module/global.d.js.map +1 -1
  32. package/lib/module/index.js +1 -0
  33. package/lib/module/index.js.map +1 -1
  34. package/lib/module/index.web.js +1 -0
  35. package/lib/module/index.web.js.map +1 -1
  36. package/lib/module/provider-options.js +4 -0
  37. package/lib/module/provider-options.js.map +1 -0
  38. package/lib/module/service.js.map +1 -1
  39. package/lib/module/service.web.js.map +1 -1
  40. package/lib/module/use-auth.js +21 -1
  41. package/lib/module/use-auth.js.map +1 -1
  42. package/lib/typescript/commonjs/Auth.nitro.d.ts +11 -0
  43. package/lib/typescript/commonjs/Auth.nitro.d.ts.map +1 -1
  44. package/lib/typescript/commonjs/Auth.web.d.ts +4 -0
  45. package/lib/typescript/commonjs/Auth.web.d.ts.map +1 -1
  46. package/lib/typescript/commonjs/create-auth-service.d.ts +2 -1
  47. package/lib/typescript/commonjs/create-auth-service.d.ts.map +1 -1
  48. package/lib/typescript/commonjs/index.d.ts +1 -0
  49. package/lib/typescript/commonjs/index.d.ts.map +1 -1
  50. package/lib/typescript/commonjs/index.web.d.ts +1 -0
  51. package/lib/typescript/commonjs/index.web.d.ts.map +1 -1
  52. package/lib/typescript/commonjs/provider-options.d.ts +23 -0
  53. package/lib/typescript/commonjs/provider-options.d.ts.map +1 -0
  54. package/lib/typescript/commonjs/service.d.ts +2 -2
  55. package/lib/typescript/commonjs/service.d.ts.map +1 -1
  56. package/lib/typescript/commonjs/service.web.d.ts +2 -2
  57. package/lib/typescript/commonjs/service.web.d.ts.map +1 -1
  58. package/lib/typescript/commonjs/use-auth.d.ts +4 -2
  59. package/lib/typescript/commonjs/use-auth.d.ts.map +1 -1
  60. package/lib/typescript/module/Auth.nitro.d.ts +11 -0
  61. package/lib/typescript/module/Auth.nitro.d.ts.map +1 -1
  62. package/lib/typescript/module/Auth.web.d.ts +4 -0
  63. package/lib/typescript/module/Auth.web.d.ts.map +1 -1
  64. package/lib/typescript/module/create-auth-service.d.ts +2 -1
  65. package/lib/typescript/module/create-auth-service.d.ts.map +1 -1
  66. package/lib/typescript/module/index.d.ts +1 -0
  67. package/lib/typescript/module/index.d.ts.map +1 -1
  68. package/lib/typescript/module/index.web.d.ts +1 -0
  69. package/lib/typescript/module/index.web.d.ts.map +1 -1
  70. package/lib/typescript/module/provider-options.d.ts +23 -0
  71. package/lib/typescript/module/provider-options.d.ts.map +1 -0
  72. package/lib/typescript/module/service.d.ts +2 -2
  73. package/lib/typescript/module/service.d.ts.map +1 -1
  74. package/lib/typescript/module/service.web.d.ts +2 -2
  75. package/lib/typescript/module/service.web.d.ts.map +1 -1
  76. package/lib/typescript/module/use-auth.d.ts +4 -2
  77. package/lib/typescript/module/use-auth.d.ts.map +1 -1
  78. package/nitrogen/generated/shared/c++/AuthUser.hpp +17 -1
  79. package/nitrogen/generated/shared/c++/HybridAuthSpec.cpp +1 -0
  80. package/nitrogen/generated/shared/c++/HybridAuthSpec.hpp +1 -0
  81. package/nitrogen/generated/shared/c++/LoginOptions.hpp +25 -1
  82. package/package.json +2 -2
  83. package/src/Auth.nitro.ts +11 -0
  84. package/src/Auth.web.ts +99 -16
  85. package/src/create-auth-service.ts +19 -9
  86. package/src/global.d.ts +2 -1
  87. package/src/index.ts +1 -0
  88. package/src/index.web.ts +1 -0
  89. package/src/provider-options.ts +62 -0
  90. package/src/service.ts +2 -1
  91. package/src/service.web.ts +2 -2
  92. package/src/use-auth.ts +22 -8
package/src/Auth.web.ts CHANGED
@@ -54,6 +54,7 @@ type WebStorageDriver = {
54
54
  type AppleAuthResponse = {
55
55
  authorization: {
56
56
  id_token: string;
57
+ code?: string;
57
58
  };
58
59
  user?: {
59
60
  email?: string;
@@ -222,6 +223,8 @@ class AuthWeb implements Auth {
222
223
  private _refreshPromise: Promise<AuthTokens> | undefined;
223
224
  private _pendingGoogleNonce: string | undefined;
224
225
  private _loginInFlight: boolean = false;
226
+ private _sessionGeneration = 0;
227
+ private _disposed = false;
225
228
 
226
229
  constructor() {
227
230
  this._config = getConfig();
@@ -379,6 +382,7 @@ class AuthWeb implements Auth {
379
382
  delete safeUser.accessToken;
380
383
  delete safeUser.idToken;
381
384
  delete safeUser.serverAuthCode;
385
+ delete safeUser.authorizationCode;
382
386
  return safeUser;
383
387
  }
384
388
 
@@ -415,6 +419,7 @@ class AuthWeb implements Auth {
415
419
  delete safeUser.accessToken;
416
420
  delete safeUser.idToken;
417
421
  delete safeUser.serverAuthCode;
422
+ delete safeUser.authorizationCode;
418
423
  this._currentUser = safeUser;
419
424
  }
420
425
  } catch (error) {
@@ -495,6 +500,9 @@ class AuthWeb implements Auth {
495
500
  private async runLoginOperation(
496
501
  operation: () => Promise<void>,
497
502
  ): Promise<void> {
503
+ if (this._disposed) {
504
+ throw new AuthWebError("cancelled", "Auth module disposed");
505
+ }
498
506
  if (this._loginInFlight) {
499
507
  throw new AuthWebError(
500
508
  "operation_in_progress",
@@ -510,14 +518,21 @@ class AuthWeb implements Auth {
510
518
  }
511
519
  }
512
520
 
521
+ private assertActiveGeneration(generation: number): void {
522
+ if (this._disposed || this._sessionGeneration !== generation) {
523
+ throw new AuthWebError("cancelled", "Auth operation was cancelled");
524
+ }
525
+ }
526
+
513
527
  async login(provider: AuthProvider, options?: LoginOptions): Promise<void> {
514
528
  const loginHint = options?.loginHint;
529
+ const generation = this._sessionGeneration;
515
530
  logger.log(`Starting login with ${provider}`, { scopes: options?.scopes });
516
531
  try {
517
532
  await this.runLoginOperation(async () => {
518
533
  if (provider === "google") {
519
534
  const scopes = options?.scopes ?? DEFAULT_SCOPES;
520
- await this.loginGoogle(scopes, loginHint);
535
+ await this.loginGoogle(scopes, loginHint, options, generation);
521
536
  return;
522
537
  }
523
538
 
@@ -528,12 +543,13 @@ class AuthWeb implements Auth {
528
543
  loginHint,
529
544
  options?.tenant,
530
545
  options?.prompt,
546
+ generation,
531
547
  );
532
548
  return;
533
549
  }
534
550
 
535
551
  if (provider === "apple") {
536
- await this.loginApple();
552
+ await this.loginApple(options, generation);
537
553
  return;
538
554
  }
539
555
 
@@ -563,13 +579,20 @@ class AuthWeb implements Auth {
563
579
  logger.log("Requesting additional scopes:", scopes);
564
580
  const newScopes = [...new Set([...this._grantedScopes, ...scopes])];
565
581
  try {
582
+ const generation = this._sessionGeneration;
566
583
  await this.runLoginOperation(async () => {
567
584
  if (provider === "google") {
568
- await this.loginGoogle(newScopes);
585
+ await this.loginGoogle(newScopes, undefined, undefined, generation);
569
586
  return;
570
587
  }
571
588
 
572
- await this.loginMicrosoft(newScopes);
589
+ await this.loginMicrosoft(
590
+ newScopes,
591
+ undefined,
592
+ undefined,
593
+ undefined,
594
+ generation,
595
+ );
573
596
  });
574
597
  } catch (e) {
575
598
  const error = this.mapError(e);
@@ -590,6 +613,10 @@ class AuthWeb implements Auth {
590
613
  }
591
614
  }
592
615
 
616
+ async revokeAccess(): Promise<void> {
617
+ this.logout();
618
+ }
619
+
593
620
  async getAccessToken(): Promise<string | undefined> {
594
621
  if (this._currentUser?.expirationTime) {
595
622
  const now = Date.now();
@@ -606,7 +633,7 @@ class AuthWeb implements Auth {
606
633
  return this._refreshPromise;
607
634
  }
608
635
 
609
- const refreshPromise = this.performRefreshToken();
636
+ const refreshPromise = this.performRefreshToken(this._sessionGeneration);
610
637
  this._refreshPromise = refreshPromise;
611
638
  try {
612
639
  return await refreshPromise;
@@ -617,7 +644,7 @@ class AuthWeb implements Auth {
617
644
  }
618
645
  }
619
646
 
620
- private async performRefreshToken(): Promise<AuthTokens> {
647
+ private async performRefreshToken(generation: number): Promise<AuthTokens> {
621
648
  if (!this._currentUser) {
622
649
  throw new Error("No user logged in");
623
650
  }
@@ -656,6 +683,7 @@ class AuthWeb implements Auth {
656
683
  });
657
684
 
658
685
  const json = await this.parseResponseObject(response);
686
+ this.assertActiveGeneration(generation);
659
687
  if (!response.ok) {
660
688
  throw new AuthWebError(
661
689
  "refresh_failed",
@@ -675,15 +703,19 @@ class AuthWeb implements Auth {
675
703
 
676
704
  const expirationTime = this.getExpirationTime(json["expires_in"]);
677
705
 
678
- const effectiveIdToken = idToken ?? this._currentUser.idToken;
706
+ const currentUser = this._currentUser;
707
+ if (!currentUser) {
708
+ throw new AuthWebError("cancelled", "Auth operation was cancelled");
709
+ }
710
+ const effectiveIdToken = idToken ?? currentUser.idToken;
679
711
  const claims = effectiveIdToken
680
712
  ? this.decodeMicrosoftJwt(effectiveIdToken)
681
713
  : {};
682
714
  const user: AuthUser = {
683
- ...this._currentUser,
715
+ ...currentUser,
684
716
  idToken: effectiveIdToken,
685
717
  accessToken: accessToken ?? undefined,
686
- refreshToken: newRefreshToken ?? this._currentUser.refreshToken,
718
+ refreshToken: newRefreshToken ?? currentUser.refreshToken,
687
719
  expirationTime,
688
720
  ...claims,
689
721
  };
@@ -706,9 +738,15 @@ class AuthWeb implements Auth {
706
738
  }
707
739
 
708
740
  logger.log("Refreshing tokens...");
709
- await this.loginGoogle(
710
- this._grantedScopes.length > 0 ? this._grantedScopes : DEFAULT_SCOPES,
741
+ await this.runLoginOperation(() =>
742
+ this.loginGoogle(
743
+ this._grantedScopes.length > 0 ? this._grantedScopes : DEFAULT_SCOPES,
744
+ undefined,
745
+ undefined,
746
+ generation,
747
+ ),
711
748
  );
749
+ this.assertActiveGeneration(generation);
712
750
  const tokens: AuthTokens = {
713
751
  accessToken: this._currentUser.accessToken,
714
752
  idToken: this._currentUser.idToken,
@@ -942,6 +980,8 @@ class AuthWeb implements Auth {
942
980
  private async loginGoogle(
943
981
  scopes: string[],
944
982
  loginHint?: string,
983
+ options?: LoginOptions,
984
+ generation?: number,
945
985
  ): Promise<void> {
946
986
  const clientId = this._config.googleWebClientId;
947
987
 
@@ -951,7 +991,7 @@ class AuthWeb implements Auth {
951
991
  );
952
992
  }
953
993
 
954
- const nonce = crypto.randomUUID();
994
+ const nonce = options?.nonce ?? crypto.randomUUID();
955
995
  this._pendingGoogleNonce = nonce;
956
996
  return new Promise((resolve, reject) => {
957
997
  const redirectUri = window.location.origin;
@@ -962,11 +1002,20 @@ class AuthWeb implements Auth {
962
1002
  authUrl.searchParams.set("scope", scopes.join(" "));
963
1003
  authUrl.searchParams.set("nonce", nonce);
964
1004
  authUrl.searchParams.set("access_type", "offline");
965
- authUrl.searchParams.set("prompt", "consent");
1005
+ authUrl.searchParams.set(
1006
+ "prompt",
1007
+ options?.forceAccountPicker ? "select_account consent" : "consent",
1008
+ );
966
1009
 
967
1010
  if (loginHint) {
968
1011
  authUrl.searchParams.set("login_hint", loginHint);
969
1012
  }
1013
+ if (options?.hostedDomain) {
1014
+ authUrl.searchParams.set("hd", options.hostedDomain);
1015
+ }
1016
+ if (options?.openIDRealm) {
1017
+ authUrl.searchParams.set("openid.realm", options.openIDRealm);
1018
+ }
970
1019
 
971
1020
  const width = 500;
972
1021
  const height = 600;
@@ -1015,6 +1064,10 @@ class AuthWeb implements Auth {
1015
1064
  }
1016
1065
  this._pendingGoogleNonce = undefined;
1017
1066
 
1067
+ if (generation !== undefined) {
1068
+ this.assertActiveGeneration(generation);
1069
+ }
1070
+
1018
1071
  this._grantedScopes = scopes;
1019
1072
  this.saveValue(SCOPES_KEY, JSON.stringify(scopes));
1020
1073
 
@@ -1023,6 +1076,8 @@ class AuthWeb implements Auth {
1023
1076
  idToken,
1024
1077
  accessToken: accessToken ?? undefined,
1025
1078
  serverAuthCode: code ?? undefined,
1079
+ userId: getOptionalString(decoded, "sub"),
1080
+ hostedDomain: getOptionalString(decoded, "hd"),
1026
1081
  scopes,
1027
1082
  expirationTime: this.getExpirationTime(expiresIn),
1028
1083
  ...this.decodeGoogleJwt(idToken),
@@ -1045,6 +1100,8 @@ class AuthWeb implements Auth {
1045
1100
  email: getOptionalString(decoded, "email"),
1046
1101
  name: getOptionalString(decoded, "name"),
1047
1102
  photo: getOptionalString(decoded, "picture"),
1103
+ userId: getOptionalString(decoded, "sub"),
1104
+ hostedDomain: getOptionalString(decoded, "hd"),
1048
1105
  };
1049
1106
  } catch (error) {
1050
1107
  logger.warn("Failed to decode Google ID token", { error: String(error) });
@@ -1057,6 +1114,7 @@ class AuthWeb implements Auth {
1057
1114
  loginHint?: string,
1058
1115
  tenant?: string,
1059
1116
  prompt?: string,
1117
+ generation?: number,
1060
1118
  ): Promise<void> {
1061
1119
  const clientId = this._config.microsoftClientId;
1062
1120
 
@@ -1156,6 +1214,7 @@ class AuthWeb implements Auth {
1156
1214
  effectiveTenant,
1157
1215
  nonce,
1158
1216
  effectiveScopes,
1217
+ generation,
1159
1218
  );
1160
1219
  },
1161
1220
  )
@@ -1194,6 +1253,7 @@ class AuthWeb implements Auth {
1194
1253
  tenant: string,
1195
1254
  expectedNonce: string,
1196
1255
  scopes: string[],
1256
+ generation?: number,
1197
1257
  ): Promise<void> {
1198
1258
  const authBaseUrl = this.getMicrosoftAuthBaseUrl(
1199
1259
  tenant,
@@ -1218,6 +1278,9 @@ class AuthWeb implements Auth {
1218
1278
  });
1219
1279
 
1220
1280
  const json = await this.parseResponseObject(response);
1281
+ if (generation !== undefined) {
1282
+ this.assertActiveGeneration(generation);
1283
+ }
1221
1284
 
1222
1285
  if (!response.ok) {
1223
1286
  throw new AuthWebError(
@@ -1352,7 +1415,10 @@ class AuthWeb implements Auth {
1352
1415
  return _appleSdkLoadPromise;
1353
1416
  }
1354
1417
 
1355
- private async loginApple(): Promise<void> {
1418
+ private async loginApple(
1419
+ options?: LoginOptions,
1420
+ generation?: number,
1421
+ ): Promise<void> {
1356
1422
  const clientId = this._config.appleWebClientId;
1357
1423
 
1358
1424
  if (!clientId) {
@@ -1368,16 +1434,24 @@ class AuthWeb implements Auth {
1368
1434
 
1369
1435
  window.AppleID.auth.init({
1370
1436
  clientId,
1371
- scope: "name email",
1437
+ scope: (options?.scopes?.length
1438
+ ? options.scopes
1439
+ : ["name", "email"]
1440
+ ).join(" "),
1372
1441
  redirectURI: window.location.origin,
1442
+ nonce: options?.nonce,
1373
1443
  usePopup: true,
1374
1444
  });
1375
1445
 
1376
1446
  try {
1377
1447
  const response: AppleAuthResponse = await window.AppleID.auth.signIn();
1448
+ if (generation !== undefined) {
1449
+ this.assertActiveGeneration(generation);
1450
+ }
1378
1451
  const user: AuthUser = {
1379
1452
  provider: "apple",
1380
1453
  idToken: response.authorization.id_token,
1454
+ authorizationCode: response.authorization.code,
1381
1455
  email: response.user?.email,
1382
1456
  name: response.user?.name
1383
1457
  ? `${response.user.name.firstName} ${response.user.name.lastName}`.trim()
@@ -1404,8 +1478,12 @@ class AuthWeb implements Auth {
1404
1478
  }
1405
1479
 
1406
1480
  logout(): void {
1481
+ this._sessionGeneration++;
1407
1482
  this._currentUser = undefined;
1408
1483
  this._grantedScopes = [];
1484
+ this._refreshPromise = undefined;
1485
+ this._pendingGoogleNonce = undefined;
1486
+ this._loginInFlight = false;
1409
1487
  this.removeFromCache(CACHE_KEY);
1410
1488
  this.removeFromCache(SCOPES_KEY);
1411
1489
  this.removeFromCache(MS_REFRESH_TOKEN_KEY);
@@ -1433,7 +1511,12 @@ class AuthWeb implements Auth {
1433
1511
  }
1434
1512
 
1435
1513
  name = "Auth";
1436
- dispose() {}
1514
+ dispose() {
1515
+ this._disposed = true;
1516
+ this.logout();
1517
+ this._listeners = [];
1518
+ this._tokenListeners = [];
1519
+ }
1437
1520
  equals(other: unknown) {
1438
1521
  return other === this;
1439
1522
  }
@@ -1,10 +1,5 @@
1
- import type {
2
- Auth,
3
- AuthProvider,
4
- AuthTokens,
5
- LoginOptions,
6
- AuthUser,
7
- } from "./Auth.nitro";
1
+ import type { Auth, AuthProvider, AuthTokens, AuthUser } from "./Auth.nitro";
2
+ import type { ProviderLoginOptions, TypedAuth } from "./provider-options";
8
3
  import { AuthError } from "./utils/auth-error";
9
4
 
10
5
  type AuthSource = () => Auth;
@@ -13,6 +8,7 @@ type AuthWithOptionalNativeMembers = Auth & {
13
8
  callback: (user: AuthUser | undefined) => void,
14
9
  ) => () => void;
15
10
  onTokensRefreshed?: (callback: (tokens: AuthTokens) => void) => () => void;
11
+ revokeAccess?: () => Promise<void>;
16
12
  setLoggingEnabled?: (enabled: boolean) => void;
17
13
  };
18
14
 
@@ -32,7 +28,7 @@ function wrapSyncAuthOperation<T>(operation: () => T): T {
32
28
  }
33
29
  }
34
30
 
35
- export function createAuthService(getAuth: AuthSource): Auth {
31
+ export function createAuthService(getAuth: AuthSource): TypedAuth {
36
32
  return {
37
33
  get name() {
38
34
  return wrapSyncAuthOperation(() => getAuth().name);
@@ -53,7 +49,10 @@ export function createAuthService(getAuth: AuthSource): Auth {
53
49
  return wrapSyncAuthOperation(() => getAuth().hasPlayServices);
54
50
  },
55
51
 
56
- login(provider: AuthProvider, options?: LoginOptions) {
52
+ login<Provider extends AuthProvider>(
53
+ provider: Provider,
54
+ options?: ProviderLoginOptions<Provider>,
55
+ ) {
57
56
  return wrapAuthOperation(() => getAuth().login(provider, options));
58
57
  },
59
58
 
@@ -65,6 +64,17 @@ export function createAuthService(getAuth: AuthSource): Auth {
65
64
  return wrapAuthOperation(() => getAuth().revokeScopes(scopes));
66
65
  },
67
66
 
67
+ revokeAccess() {
68
+ return wrapAuthOperation(async () => {
69
+ const auth = getAuth() as AuthWithOptionalNativeMembers;
70
+ if (auth.revokeAccess) {
71
+ await auth.revokeAccess();
72
+ return;
73
+ }
74
+ auth.logout();
75
+ });
76
+ },
77
+
68
78
  getAccessToken() {
69
79
  return wrapAuthOperation(() => getAuth().getAccessToken());
70
80
  },
package/src/global.d.ts CHANGED
@@ -6,10 +6,11 @@ declare global {
6
6
  clientId: string;
7
7
  scope: string;
8
8
  redirectURI: string;
9
+ nonce?: string;
9
10
  usePopup: boolean;
10
11
  }) => void;
11
12
  signIn: () => Promise<{
12
- authorization: { id_token: string };
13
+ authorization: { id_token: string; code?: string };
13
14
  user?: {
14
15
  email?: string;
15
16
  name?: {
package/src/index.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  export * from "./Auth.nitro";
2
+ export * from "./provider-options";
2
3
  export * from "./ui/social-button";
3
4
  export { useAuth, type UseAuthReturn } from "./use-auth";
4
5
  export { AuthService } from "./service";
package/src/index.web.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  export * from "./Auth.nitro";
2
+ export * from "./provider-options";
2
3
  export * from "./ui/social-button.web";
3
4
  export { useAuth, type UseAuthReturn } from "./use-auth";
4
5
  export { AuthService } from "./service.web";
@@ -0,0 +1,62 @@
1
+ import type { Auth, AuthProvider, LoginOptions } from "./Auth.nitro";
2
+
3
+ type StrictLoginOptions<AllowedKeys extends keyof LoginOptions> = Pick<
4
+ LoginOptions,
5
+ AllowedKeys
6
+ > &
7
+ Partial<Record<Exclude<keyof LoginOptions, AllowedKeys>, never>>;
8
+
9
+ type GoogleCommonKeys =
10
+ | "scopes"
11
+ | "loginHint"
12
+ | "nonce"
13
+ | "forceAccountPicker"
14
+ | "hostedDomain";
15
+
16
+ export type GoogleIOSLoginOptions = StrictLoginOptions<
17
+ GoogleCommonKeys | "useSheet" | "openIDRealm"
18
+ >;
19
+
20
+ export type GoogleAndroidLoginOptions = StrictLoginOptions<
21
+ | GoogleCommonKeys
22
+ | "useOneTap"
23
+ | "filterByAuthorizedAccounts"
24
+ | "useLegacyGoogleSignIn"
25
+ | "forceCodeForRefreshToken"
26
+ | "requestVerifiedPhoneNumber"
27
+ >;
28
+
29
+ export type GoogleWebLoginOptions = StrictLoginOptions<
30
+ GoogleCommonKeys | "openIDRealm"
31
+ >;
32
+
33
+ export type GoogleLoginOptions =
34
+ | GoogleIOSLoginOptions
35
+ | GoogleAndroidLoginOptions
36
+ | GoogleWebLoginOptions;
37
+
38
+ export type AppleIOSLoginOptions = StrictLoginOptions<"scopes" | "nonce">;
39
+ export type AppleWebLoginOptions = AppleIOSLoginOptions;
40
+ export type AppleLoginOptions = AppleIOSLoginOptions | AppleWebLoginOptions;
41
+
42
+ export type MicrosoftLoginOptions = StrictLoginOptions<
43
+ "scopes" | "loginHint" | "tenant" | "prompt"
44
+ >;
45
+
46
+ export type LoginOptionsByProvider = {
47
+ google: GoogleLoginOptions;
48
+ apple: AppleLoginOptions;
49
+ microsoft: MicrosoftLoginOptions;
50
+ };
51
+
52
+ export type ProviderLoginOptions<Provider extends AuthProvider> =
53
+ LoginOptionsByProvider[Provider];
54
+
55
+ export type AuthLogin = <Provider extends AuthProvider>(
56
+ provider: Provider,
57
+ options?: ProviderLoginOptions<Provider>,
58
+ ) => Promise<void>;
59
+
60
+ export type TypedAuth = Omit<Auth, "login"> & {
61
+ login: AuthLogin;
62
+ };
package/src/service.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { NitroModules } from "react-native-nitro-modules";
2
2
  import type { Auth } from "./Auth.nitro";
3
3
  import { createAuthService } from "./create-auth-service";
4
+ import type { TypedAuth } from "./provider-options";
4
5
 
5
6
  let nitroAuth: Auth | undefined;
6
7
 
@@ -9,4 +10,4 @@ function getNitroAuth(): Auth {
9
10
  return nitroAuth;
10
11
  }
11
12
 
12
- export const AuthService: Auth = createAuthService(getNitroAuth);
13
+ export const AuthService: TypedAuth = createAuthService(getNitroAuth);
@@ -1,5 +1,5 @@
1
- import type { Auth } from "./Auth.nitro";
2
1
  import { AuthModule } from "./Auth.web";
3
2
  import { createAuthService } from "./create-auth-service";
3
+ import type { TypedAuth } from "./provider-options";
4
4
 
5
- export const AuthService: Auth = createAuthService(() => AuthModule);
5
+ export const AuthService: TypedAuth = createAuthService(() => AuthModule);
package/src/use-auth.ts CHANGED
@@ -1,10 +1,6 @@
1
1
  import { useState, useEffect, useCallback, useMemo } from "react";
2
- import type {
3
- AuthUser,
4
- AuthProvider,
5
- LoginOptions,
6
- AuthTokens,
7
- } from "./Auth.nitro";
2
+ import type { AuthUser, AuthProvider, AuthTokens } from "./Auth.nitro";
3
+ import type { AuthLogin, ProviderLoginOptions } from "./provider-options";
8
4
  import { AuthService } from "./service";
9
5
  import { AuthError } from "./utils/auth-error";
10
6
 
@@ -45,10 +41,11 @@ const areScopesEqual = (left: string[], right: string[]): boolean => {
45
41
 
46
42
  export type UseAuthReturn = AuthState & {
47
43
  hasPlayServices: boolean;
48
- login: (provider: AuthProvider, options?: LoginOptions) => Promise<void>;
44
+ login: AuthLogin;
49
45
  logout: () => void;
50
46
  requestScopes: (scopes: string[]) => Promise<void>;
51
47
  revokeScopes: (scopes: string[]) => Promise<void>;
48
+ revokeAccess: () => Promise<void>;
52
49
  getAccessToken: () => Promise<string | undefined>;
53
50
  refreshToken: () => Promise<AuthTokens>;
54
51
  silentRestore: () => Promise<void>;
@@ -87,7 +84,10 @@ export function useAuth(): UseAuthReturn {
87
84
  );
88
85
 
89
86
  const login = useCallback(
90
- async (provider: AuthProvider, options?: LoginOptions) => {
87
+ async <Provider extends AuthProvider>(
88
+ provider: Provider,
89
+ options?: ProviderLoginOptions<Provider>,
90
+ ) => {
91
91
  setState((prev) => ({ ...prev, loading: true, error: undefined }));
92
92
  try {
93
93
  await AuthService.login(provider, options);
@@ -151,6 +151,18 @@ export function useAuth(): UseAuthReturn {
151
151
  [syncStateFromService],
152
152
  );
153
153
 
154
+ const revokeAccess = useCallback(async () => {
155
+ setState((prev) => ({ ...prev, loading: true, error: undefined }));
156
+ try {
157
+ await AuthService.revokeAccess();
158
+ syncStateFromService(false, undefined);
159
+ } catch (e) {
160
+ const error = AuthError.from(e);
161
+ setState((prev) => ({ ...prev, loading: false, error }));
162
+ throw error;
163
+ }
164
+ }, [syncStateFromService]);
165
+
154
166
  const getAccessToken = useCallback(() => AuthService.getAccessToken(), []);
155
167
 
156
168
  const refreshToken = useCallback(async () => {
@@ -214,6 +226,7 @@ export function useAuth(): UseAuthReturn {
214
226
  logout,
215
227
  requestScopes,
216
228
  revokeScopes,
229
+ revokeAccess,
217
230
  getAccessToken,
218
231
  refreshToken,
219
232
  silentRestore,
@@ -224,6 +237,7 @@ export function useAuth(): UseAuthReturn {
224
237
  logout,
225
238
  requestScopes,
226
239
  revokeScopes,
240
+ revokeAccess,
227
241
  getAccessToken,
228
242
  refreshToken,
229
243
  silentRestore,