@shware/security 4.0.0 → 5.0.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 (82) hide show
  1. package/README.md +110 -99
  2. package/dist/auth/index.cjs +44 -36
  3. package/dist/auth/index.cjs.map +1 -1
  4. package/dist/auth/index.d.cts +6 -6
  5. package/dist/auth/index.d.cts.map +1 -1
  6. package/dist/auth/index.d.mts +6 -6
  7. package/dist/auth/index.d.mts.map +1 -1
  8. package/dist/auth/index.mjs +44 -36
  9. package/dist/auth/index.mjs.map +1 -1
  10. package/dist/auth/types.d.cts +12 -7
  11. package/dist/auth/types.d.cts.map +1 -1
  12. package/dist/auth/types.d.mts +12 -7
  13. package/dist/auth/types.d.mts.map +1 -1
  14. package/dist/index.cjs +4 -1
  15. package/dist/index.d.cts +3 -2
  16. package/dist/index.d.mts +3 -2
  17. package/dist/index.mjs +3 -2
  18. package/dist/oauth2/client.cjs +113 -49
  19. package/dist/oauth2/client.cjs.map +1 -1
  20. package/dist/oauth2/client.d.cts +54 -14
  21. package/dist/oauth2/client.d.cts.map +1 -1
  22. package/dist/oauth2/client.d.mts +54 -14
  23. package/dist/oauth2/client.d.mts.map +1 -1
  24. package/dist/oauth2/client.mjs +113 -49
  25. package/dist/oauth2/client.mjs.map +1 -1
  26. package/dist/oauth2/name.cjs +107 -0
  27. package/dist/oauth2/name.cjs.map +1 -0
  28. package/dist/oauth2/name.d.cts +49 -0
  29. package/dist/oauth2/name.d.cts.map +1 -0
  30. package/dist/oauth2/name.d.mts +49 -0
  31. package/dist/oauth2/name.d.mts.map +1 -0
  32. package/dist/oauth2/name.mjs +101 -0
  33. package/dist/oauth2/name.mjs.map +1 -0
  34. package/dist/oauth2/provider/apple-client-secret.cjs +3 -3
  35. package/dist/oauth2/provider/apple-client-secret.cjs.map +1 -1
  36. package/dist/oauth2/provider/apple-client-secret.d.cts +3 -3
  37. package/dist/oauth2/provider/apple-client-secret.d.mts +3 -3
  38. package/dist/oauth2/provider/apple-client-secret.mjs +3 -3
  39. package/dist/oauth2/provider/apple-client-secret.mjs.map +1 -1
  40. package/dist/oauth2/provider/apple.cjs +38 -10
  41. package/dist/oauth2/provider/apple.cjs.map +1 -1
  42. package/dist/oauth2/provider/apple.d.cts +19 -14
  43. package/dist/oauth2/provider/apple.d.cts.map +1 -1
  44. package/dist/oauth2/provider/apple.d.mts +19 -14
  45. package/dist/oauth2/provider/apple.d.mts.map +1 -1
  46. package/dist/oauth2/provider/apple.mjs +38 -10
  47. package/dist/oauth2/provider/apple.mjs.map +1 -1
  48. package/dist/oauth2/provider/common.cjs +13 -9
  49. package/dist/oauth2/provider/common.cjs.map +1 -1
  50. package/dist/oauth2/provider/common.d.cts +13 -2
  51. package/dist/oauth2/provider/common.d.cts.map +1 -1
  52. package/dist/oauth2/provider/common.d.mts +13 -2
  53. package/dist/oauth2/provider/common.d.mts.map +1 -1
  54. package/dist/oauth2/provider/common.mjs +13 -9
  55. package/dist/oauth2/provider/common.mjs.map +1 -1
  56. package/dist/oauth2/provider/facebook.cjs +59 -35
  57. package/dist/oauth2/provider/facebook.cjs.map +1 -1
  58. package/dist/oauth2/provider/facebook.d.cts.map +1 -1
  59. package/dist/oauth2/provider/facebook.d.mts.map +1 -1
  60. package/dist/oauth2/provider/facebook.mjs +59 -35
  61. package/dist/oauth2/provider/facebook.mjs.map +1 -1
  62. package/dist/oauth2/provider/google.cjs +31 -32
  63. package/dist/oauth2/provider/google.cjs.map +1 -1
  64. package/dist/oauth2/provider/google.d.cts.map +1 -1
  65. package/dist/oauth2/provider/google.d.mts.map +1 -1
  66. package/dist/oauth2/provider/google.mjs +31 -32
  67. package/dist/oauth2/provider/google.mjs.map +1 -1
  68. package/dist/oauth2/provider/index.cjs +1 -1
  69. package/dist/oauth2/provider/index.mjs +1 -1
  70. package/dist/oauth2/provider/wechat.cjs +1 -0
  71. package/dist/oauth2/provider/wechat.cjs.map +1 -1
  72. package/dist/oauth2/provider/wechat.d.cts.map +1 -1
  73. package/dist/oauth2/provider/wechat.d.mts.map +1 -1
  74. package/dist/oauth2/provider/wechat.mjs +1 -0
  75. package/dist/oauth2/provider/wechat.mjs.map +1 -1
  76. package/dist/oauth2/types.cjs.map +1 -1
  77. package/dist/oauth2/types.d.cts +100 -33
  78. package/dist/oauth2/types.d.cts.map +1 -1
  79. package/dist/oauth2/types.d.mts +100 -33
  80. package/dist/oauth2/types.d.mts.map +1 -1
  81. package/dist/oauth2/types.mjs.map +1 -1
  82. package/package.json +1 -1
@@ -6,7 +6,8 @@ export interface PkceParameters {
6
6
  }
7
7
  export interface OAuth2AuthorizationRequest {
8
8
  state: string;
9
- registrationId: string;
9
+ /** Key of the provider in `OAuth2ClientConfig.providers` the flow was started for. */
10
+ provider: string;
10
11
  authorizationRequestUri: string;
11
12
  additionalParameters: PkceParameters;
12
13
  /**
@@ -26,23 +27,28 @@ interface CreateAuthorizationUriParams {
26
27
  export interface ExchangeCodeParams {
27
28
  code: string;
28
29
  clientId: string;
29
- clientSecret: string;
30
+ /** Absent for public clients (Google's installed-app clients, PKCE-only clients). */
31
+ clientSecret?: string;
30
32
  redirectUri: string;
31
33
  pkce?: Omit<PkceParameters, 'code_challenge' | 'code_challenge_method'>;
32
34
  }
33
35
  export interface RefreshTokenParams {
34
36
  clientId: string;
35
- clientSecret: string;
37
+ clientSecret?: string;
36
38
  refreshToken: string;
37
39
  }
38
40
  export interface RevokeTokenParams {
39
41
  token: string;
40
42
  clientId: string;
41
- clientSecret: string;
43
+ clientSecret?: string;
42
44
  }
43
45
  export interface LoginOAuth2NativeParams {
46
+ /**
47
+ * The configured client the app signs in as (its `client_id`, or the provider's default native
48
+ * client). Id tokens must be issued to it: it is the only audience accepted.
49
+ */
44
50
  clientId: string;
45
- clientSecret: string;
51
+ clientSecret?: string;
46
52
  redirectUri: string;
47
53
  pkce?: PkceParameters;
48
54
  credentials: NativeCredential;
@@ -91,7 +97,36 @@ export type NativeCredential = {
91
97
  redirect_uri?: string;
92
98
  id_token?: string;
93
99
  access_token?: string;
100
+ /**
101
+ * The user's name as the platform hands it to the app, for providers whose id token carries none
102
+ * (Apple sends it on the first authorization only): iOS
103
+ * `ASAuthorizationAppleIDCredential.fullName`, expo-apple-authentication's `credential.fullName`.
104
+ * The snake_case fields above are OAuth / OIDC protocol parameters; this one is not, it is the
105
+ * platform's object passed through unchanged, so it keeps the platform's own name and apps send
106
+ * `fullName: credential.fullName` as is. Unsigned client input: the provider cleans each part and
107
+ * ignores anything that is not a string. Parts with a standard claim become `given_name`,
108
+ * `family_name`, `middle_name` and `nickname`; `namePrefix` / `nameSuffix` have none and are kept
109
+ * in `userInfo.data.fullName` only.
110
+ */
111
+ fullName?: PersonNameComponents;
94
112
  };
113
+ /** iOS `PersonNameComponents` as JSON; every part may be missing or `null`. */
114
+ export interface PersonNameComponents {
115
+ givenName?: string | null;
116
+ familyName?: string | null;
117
+ middleName?: string | null;
118
+ namePrefix?: string | null;
119
+ nameSuffix?: string | null;
120
+ nickname?: string | null;
121
+ }
122
+ /**
123
+ * Fields of the authorization response besides `code` and `state` that a provider uses to fill in
124
+ * the user info: Apple posts the user's name as `user` (JSON) with the first authorization only,
125
+ * since its id token never carries one. Unsigned, so treated as untrusted input.
126
+ */
127
+ export interface AuthorizationResponse {
128
+ user?: string;
129
+ }
95
130
  export declare const OIDC_SCOPES: readonly ['openid', 'profile', 'email', 'phone', 'address', 'offline_access'];
96
131
  export type OidcScope = (typeof OIDC_SCOPES)[number];
97
132
  export interface StandardClaims {
@@ -157,8 +192,12 @@ export interface Provider {
157
192
  createAuthorizationUri: (params: CreateAuthorizationUriParams) => URL;
158
193
  /** step 2: exchange code for token */
159
194
  exchangeAuthorizationCode: (params: ExchangeCodeParams) => Promise<OAuth2Token>;
160
- /** step 3: get user info */
161
- getUserInfo: (token: OAuth2Token) => Promise<UserInfo>;
195
+ /**
196
+ * step 3: get user info. `context.clientId` is the client the token was issued to, the only
197
+ * audience an id token may carry; `context.response` holds what the authorization response
198
+ * carried besides the code, for the providers that send user data there (Apple).
199
+ */
200
+ getUserInfo: (token: OAuth2Token, context: UserInfoContext) => Promise<UserInfo>;
162
201
  /** others: refresh access token */
163
202
  refreshAccessToken?: (params: RefreshTokenParams) => Promise<OAuth2Token>;
164
203
  /** others: revoke token */
@@ -168,45 +207,73 @@ export interface Provider {
168
207
  userInfo: UserInfo;
169
208
  }>;
170
209
  }
210
+ export interface UserInfoContext {
211
+ clientId: string;
212
+ response?: AuthorizationResponse;
213
+ }
171
214
  export interface OneTapProvider extends Provider {
172
- getTokenInfo: (id_token: string) => Promise<{
215
+ /** Verifies a One Tap / FedCM credential, which must be issued to `clientId` (the web client). */
216
+ getTokenInfo: (id_token: string, clientId: string) => Promise<{
173
217
  token: OAuth2Token;
174
218
  userInfo: UserInfo;
175
219
  }>;
176
220
  }
177
- export interface Registration {
178
- /**
179
- * Reference to the OAuth 2.0 provider to use. May reference an element from the 'provider'
180
- * property or used one of the commonly used providers (google, github, facebook, okta).
181
- * */
182
- provider?: string;
183
- /** Client ID for the registration. */
221
+ /**
222
+ * A client secret: a fixed string, or a function minting one for the client id it is called with
223
+ * (Sign in with Apple's signed JWT, see `createAppleClientSecret`), called on every use so it can
224
+ * cache and renew on its own.
225
+ */
226
+ export type ClientSecret = string | ((clientId: string) => string | Promise<string>);
227
+ /** The client a provider's server-side flows sign in as: the redirect flow and Google One Tap. */
228
+ export interface WebClient {
184
229
  clientId: string;
185
- /** Client secret of the registration. */
186
- clientSecret: string;
187
- /** Client authentication method. May be left blank when using a pre-defined provider. */
188
- clientAuthenticationMethod?: string;
189
- /** Authorization grant type. May be left blank when using a pre-defined provider. */
190
- authorizationGrantType?: 'authorization_code' | 'client_credentials' | 'device_code' | 'jwt_bearer' | 'password' | 'refresh_token' | 'token_exchange';
191
- /** Redirect URI. May be left blank when using a pre-defined provider. */
230
+ /** Absent for a public client. */
231
+ clientSecret?: ClientSecret;
232
+ /** Default: `${baseUri}/login/oauth2/code/<provider key>`. */
192
233
  redirectUri?: string;
193
- /** Authorization scopes. When left blank the provider's default scopes, if any, will be used. */
234
+ /** Authorization scopes. Default: the provider's `defaultScope`. */
194
235
  scope?: string[];
195
- /** Client name. May be left blank when using a pre-defined provider. */
196
- clientName?: string;
197
236
  }
237
+ /**
238
+ * A client an app signs in as on the device (an iOS bundle id, a Google iOS / Android client) and
239
+ * whose code or id token it posts to the native login route.
240
+ */
241
+ export interface NativeClient {
242
+ clientId: string;
243
+ /** Absent for a public client (Google's installed-app clients have none). */
244
+ clientSecret?: ClientSecret;
245
+ /**
246
+ * Redirect URI sent with the code exchange when the app sends no `redirect_uri` of its own.
247
+ * Default: `${baseUri}/login/oauth2/code/<provider key>`.
248
+ */
249
+ redirectUri?: string;
250
+ }
251
+ /**
252
+ * One identity source: every user it signs in has a `sub` unique within it, whichever client they
253
+ * came through. The key in `OAuth2ClientConfig.providers` names it in the routes and in
254
+ * `onAuthorized`. Two keys may share an implementation (two Google Cloud projects, one Okta per
255
+ * tenant) when their subjects are separate namespaces.
256
+ */
257
+ export interface ProviderConfig {
258
+ /** The implementation: `apple`, `google`, `github`, ... from `@shware/security/oauth2/provider`. */
259
+ provider: Provider;
260
+ /** The redirect flow's and One Tap's client. Required by those flows. */
261
+ web?: WebClient;
262
+ /**
263
+ * Clients the native login accepts besides `web`. An app names its client with `client_id`;
264
+ * without one, the only native client is used, or `web` when there is none.
265
+ */
266
+ native?: NativeClient[];
267
+ }
268
+ export type ProvidersConfig = {
269
+ [key: string]: ProviderConfig | undefined;
270
+ };
198
271
  export interface OAuth2ClientConfig {
199
272
  baseUri: string;
200
273
  errorUri: string;
201
274
  successUri: string;
202
- provider: {
203
- [name: string]: Provider | undefined;
204
- };
205
- registration: {
206
- [name: string]: Registration | undefined;
207
- } | (() => Promise<{
208
- [name: string]: Registration | undefined;
209
- }>);
275
+ /** Providers by key; a function is called per request, for secrets read at request time. */
276
+ providers: ProvidersConfig | (() => Promise<ProvidersConfig>);
210
277
  }
211
278
  //#endregion
212
279
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.cts","names":[],"sources":["../../src/oauth2/types.ts"],"mappings":";iBACiB;EACf;EACA;EACA;;iBAGe;EACf;EACA;EACA;EACA,sBAAsB;;;;;;EAMtB,aAAa;;UAGL;EACR;EACA;EACA;EACA;EACA,OAAO,KAAK;;iBAGG;EACf;EACA;EACA;EACA;EACA,OAAO,KAAK;;iBAGG;EACf;EACA;EACA;;iBAGe;EACf;EACA;EACA;;iBAGe;EACf;EACA;EACA;EACA,OAAO;EACP,aAAa;;iBAIE;;;;;EAKf;;;;;EAMA;;;;;;;;EASA;;;;;;EAOA;;;;;;EAOA;EAEA;GAEC;;iBAGc,kBAAkB;EACjC;;YAGU;EACV;EACA;EACA;EACA;EACA;EACA;;qBAGW;YASD,oBAAoB;iBAGf;EACf;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;IACE;IACA;IACA;IACA;IACA;IACA;;EAEF;;iBAGe,SAAS;EACxB,QAAQ;EACR,MAAM;;iBAGS;;EAEf;;EAGA;;EAGA;;EAGA;;EAGA;;EAGA;;;;EAKA;;EAGA;;;;;EAMA;;EAGA;;EAGA,yBAAyB,QAAQ,iCAAiC;;EAGlE,4BAA4B,QAAQ,uBAAuB,QAAQ;;EAGnE,cAAc,OAAO,gBAAgB,QAAQ;;EAG7C,sBAAsB,QAAQ,uBAAuB,QAAQ;;EAG7D,eAAe,QAAQ,sBAAsB;EAE7C,qBACE,QAAQ,4BACL;IAAU,OAAO;IAAa,UAAU;;;iBAG9B,uBAAuB;EACtC,eAAe,qBAAqB;IAAU,OAAO;IAAa,UAAU;;;iBAG7D;;;;;EAKf;;EAGA;;EAGA;;EAGA;;EAGA;;EAYA;;EAGA;;EAGA;;iBAGe;EACf;EACA;EACA;EACA;KAAa,eAAe;;EAC5B;KACO,eAAe;aACX;KAAW,eAAe"}
1
+ {"version":3,"file":"types.d.cts","names":[],"sources":["../../src/oauth2/types.ts"],"mappings":";iBACiB;EACf;EACA;EACA;;iBAGe;EACf;;EAEA;EACA;EACA,sBAAsB;;;;;;EAMtB,aAAa;;UAGL;EACR;EACA;EACA;EACA;EACA,OAAO,KAAK;;iBAGG;EACf;EACA;;EAEA;EACA;EACA,OAAO,KAAK;;iBAGG;EACf;EACA;EACA;;iBAGe;EACf;EACA;EACA;;iBAGe;;;;;EAKf;EACA;EACA;EACA,OAAO;EACP,aAAa;;iBAIE;;;;;EAKf;;;;;EAMA;;;;;;;;EASA;;;;;;EAOA;;;;;;EAOA;EAEA;GAEC;;iBAGc,kBAAkB;EACjC;;YAGU;EACV;EACA;EACA;EACA;EACA;EACA;;;;;;;;;;;;EAYA,WAAW;;;iBAII;EACf;EACA;EACA;EACA;EACA;EACA;;;;;;;iBAQe;EACf;;qBAGW;YASD,oBAAoB;iBAGf;EACf;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;IACE;IACA;IACA;IACA;IACA;IACA;;EAEF;;iBAGe,SAAS;EACxB,QAAQ;EACR,MAAM;;iBAGS;;EAEf;;EAGA;;EAGA;;EAGA;;EAGA;;EAGA;;;;EAKA;;EAGA;;;;;EAMA;;EAGA;;EAGA,yBAAyB,QAAQ,iCAAiC;;EAGlE,4BAA4B,QAAQ,uBAAuB,QAAQ;;;;;;EAOnE,cAAc,OAAO,aAAa,SAAS,oBAAoB,QAAQ;;EAGvE,sBAAsB,QAAQ,uBAAuB,QAAQ;;EAG7D,eAAe,QAAQ,sBAAsB;EAE7C,qBACE,QAAQ,4BACL;IAAU,OAAO;IAAa,UAAU;;;iBAG9B;EACf;EACA,WAAW;;iBAGI,uBAAuB;;EAEtC,eACE,kBACA,qBACG;IAAU,OAAO;IAAa,UAAU;;;;;;;;YAQnC,0BAA0B,8BAA8B;;iBAGnD;EACf;;EAEA,eAAe;;EAEf;;EAEA;;;;;;iBAOe;EACf;;EAEA,eAAe;;;;;EAKf;;;;;;;;iBASe;;EAEf,UAAU;;EAEV,MAAM;;;;;EAKN,SAAS;;YAGC;GAAqB,cAAc;;iBAE9B;EACf;EACA;EACA;;EAEA,WAAW,yBAAyB,QAAQ"}
@@ -6,7 +6,8 @@ export interface PkceParameters {
6
6
  }
7
7
  export interface OAuth2AuthorizationRequest {
8
8
  state: string;
9
- registrationId: string;
9
+ /** Key of the provider in `OAuth2ClientConfig.providers` the flow was started for. */
10
+ provider: string;
10
11
  authorizationRequestUri: string;
11
12
  additionalParameters: PkceParameters;
12
13
  /**
@@ -26,23 +27,28 @@ interface CreateAuthorizationUriParams {
26
27
  export interface ExchangeCodeParams {
27
28
  code: string;
28
29
  clientId: string;
29
- clientSecret: string;
30
+ /** Absent for public clients (Google's installed-app clients, PKCE-only clients). */
31
+ clientSecret?: string;
30
32
  redirectUri: string;
31
33
  pkce?: Omit<PkceParameters, 'code_challenge' | 'code_challenge_method'>;
32
34
  }
33
35
  export interface RefreshTokenParams {
34
36
  clientId: string;
35
- clientSecret: string;
37
+ clientSecret?: string;
36
38
  refreshToken: string;
37
39
  }
38
40
  export interface RevokeTokenParams {
39
41
  token: string;
40
42
  clientId: string;
41
- clientSecret: string;
43
+ clientSecret?: string;
42
44
  }
43
45
  export interface LoginOAuth2NativeParams {
46
+ /**
47
+ * The configured client the app signs in as (its `client_id`, or the provider's default native
48
+ * client). Id tokens must be issued to it: it is the only audience accepted.
49
+ */
44
50
  clientId: string;
45
- clientSecret: string;
51
+ clientSecret?: string;
46
52
  redirectUri: string;
47
53
  pkce?: PkceParameters;
48
54
  credentials: NativeCredential;
@@ -91,7 +97,36 @@ export type NativeCredential = {
91
97
  redirect_uri?: string;
92
98
  id_token?: string;
93
99
  access_token?: string;
100
+ /**
101
+ * The user's name as the platform hands it to the app, for providers whose id token carries none
102
+ * (Apple sends it on the first authorization only): iOS
103
+ * `ASAuthorizationAppleIDCredential.fullName`, expo-apple-authentication's `credential.fullName`.
104
+ * The snake_case fields above are OAuth / OIDC protocol parameters; this one is not, it is the
105
+ * platform's object passed through unchanged, so it keeps the platform's own name and apps send
106
+ * `fullName: credential.fullName` as is. Unsigned client input: the provider cleans each part and
107
+ * ignores anything that is not a string. Parts with a standard claim become `given_name`,
108
+ * `family_name`, `middle_name` and `nickname`; `namePrefix` / `nameSuffix` have none and are kept
109
+ * in `userInfo.data.fullName` only.
110
+ */
111
+ fullName?: PersonNameComponents;
94
112
  };
113
+ /** iOS `PersonNameComponents` as JSON; every part may be missing or `null`. */
114
+ export interface PersonNameComponents {
115
+ givenName?: string | null;
116
+ familyName?: string | null;
117
+ middleName?: string | null;
118
+ namePrefix?: string | null;
119
+ nameSuffix?: string | null;
120
+ nickname?: string | null;
121
+ }
122
+ /**
123
+ * Fields of the authorization response besides `code` and `state` that a provider uses to fill in
124
+ * the user info: Apple posts the user's name as `user` (JSON) with the first authorization only,
125
+ * since its id token never carries one. Unsigned, so treated as untrusted input.
126
+ */
127
+ export interface AuthorizationResponse {
128
+ user?: string;
129
+ }
95
130
  export declare const OIDC_SCOPES: readonly ['openid', 'profile', 'email', 'phone', 'address', 'offline_access'];
96
131
  export type OidcScope = (typeof OIDC_SCOPES)[number];
97
132
  export interface StandardClaims {
@@ -157,8 +192,12 @@ export interface Provider {
157
192
  createAuthorizationUri: (params: CreateAuthorizationUriParams) => URL;
158
193
  /** step 2: exchange code for token */
159
194
  exchangeAuthorizationCode: (params: ExchangeCodeParams) => Promise<OAuth2Token>;
160
- /** step 3: get user info */
161
- getUserInfo: (token: OAuth2Token) => Promise<UserInfo>;
195
+ /**
196
+ * step 3: get user info. `context.clientId` is the client the token was issued to, the only
197
+ * audience an id token may carry; `context.response` holds what the authorization response
198
+ * carried besides the code, for the providers that send user data there (Apple).
199
+ */
200
+ getUserInfo: (token: OAuth2Token, context: UserInfoContext) => Promise<UserInfo>;
162
201
  /** others: refresh access token */
163
202
  refreshAccessToken?: (params: RefreshTokenParams) => Promise<OAuth2Token>;
164
203
  /** others: revoke token */
@@ -168,45 +207,73 @@ export interface Provider {
168
207
  userInfo: UserInfo;
169
208
  }>;
170
209
  }
210
+ export interface UserInfoContext {
211
+ clientId: string;
212
+ response?: AuthorizationResponse;
213
+ }
171
214
  export interface OneTapProvider extends Provider {
172
- getTokenInfo: (id_token: string) => Promise<{
215
+ /** Verifies a One Tap / FedCM credential, which must be issued to `clientId` (the web client). */
216
+ getTokenInfo: (id_token: string, clientId: string) => Promise<{
173
217
  token: OAuth2Token;
174
218
  userInfo: UserInfo;
175
219
  }>;
176
220
  }
177
- export interface Registration {
178
- /**
179
- * Reference to the OAuth 2.0 provider to use. May reference an element from the 'provider'
180
- * property or used one of the commonly used providers (google, github, facebook, okta).
181
- * */
182
- provider?: string;
183
- /** Client ID for the registration. */
221
+ /**
222
+ * A client secret: a fixed string, or a function minting one for the client id it is called with
223
+ * (Sign in with Apple's signed JWT, see `createAppleClientSecret`), called on every use so it can
224
+ * cache and renew on its own.
225
+ */
226
+ export type ClientSecret = string | ((clientId: string) => string | Promise<string>);
227
+ /** The client a provider's server-side flows sign in as: the redirect flow and Google One Tap. */
228
+ export interface WebClient {
184
229
  clientId: string;
185
- /** Client secret of the registration. */
186
- clientSecret: string;
187
- /** Client authentication method. May be left blank when using a pre-defined provider. */
188
- clientAuthenticationMethod?: string;
189
- /** Authorization grant type. May be left blank when using a pre-defined provider. */
190
- authorizationGrantType?: 'authorization_code' | 'client_credentials' | 'device_code' | 'jwt_bearer' | 'password' | 'refresh_token' | 'token_exchange';
191
- /** Redirect URI. May be left blank when using a pre-defined provider. */
230
+ /** Absent for a public client. */
231
+ clientSecret?: ClientSecret;
232
+ /** Default: `${baseUri}/login/oauth2/code/<provider key>`. */
192
233
  redirectUri?: string;
193
- /** Authorization scopes. When left blank the provider's default scopes, if any, will be used. */
234
+ /** Authorization scopes. Default: the provider's `defaultScope`. */
194
235
  scope?: string[];
195
- /** Client name. May be left blank when using a pre-defined provider. */
196
- clientName?: string;
197
236
  }
237
+ /**
238
+ * A client an app signs in as on the device (an iOS bundle id, a Google iOS / Android client) and
239
+ * whose code or id token it posts to the native login route.
240
+ */
241
+ export interface NativeClient {
242
+ clientId: string;
243
+ /** Absent for a public client (Google's installed-app clients have none). */
244
+ clientSecret?: ClientSecret;
245
+ /**
246
+ * Redirect URI sent with the code exchange when the app sends no `redirect_uri` of its own.
247
+ * Default: `${baseUri}/login/oauth2/code/<provider key>`.
248
+ */
249
+ redirectUri?: string;
250
+ }
251
+ /**
252
+ * One identity source: every user it signs in has a `sub` unique within it, whichever client they
253
+ * came through. The key in `OAuth2ClientConfig.providers` names it in the routes and in
254
+ * `onAuthorized`. Two keys may share an implementation (two Google Cloud projects, one Okta per
255
+ * tenant) when their subjects are separate namespaces.
256
+ */
257
+ export interface ProviderConfig {
258
+ /** The implementation: `apple`, `google`, `github`, ... from `@shware/security/oauth2/provider`. */
259
+ provider: Provider;
260
+ /** The redirect flow's and One Tap's client. Required by those flows. */
261
+ web?: WebClient;
262
+ /**
263
+ * Clients the native login accepts besides `web`. An app names its client with `client_id`;
264
+ * without one, the only native client is used, or `web` when there is none.
265
+ */
266
+ native?: NativeClient[];
267
+ }
268
+ export type ProvidersConfig = {
269
+ [key: string]: ProviderConfig | undefined;
270
+ };
198
271
  export interface OAuth2ClientConfig {
199
272
  baseUri: string;
200
273
  errorUri: string;
201
274
  successUri: string;
202
- provider: {
203
- [name: string]: Provider | undefined;
204
- };
205
- registration: {
206
- [name: string]: Registration | undefined;
207
- } | (() => Promise<{
208
- [name: string]: Registration | undefined;
209
- }>);
275
+ /** Providers by key; a function is called per request, for secrets read at request time. */
276
+ providers: ProvidersConfig | (() => Promise<ProvidersConfig>);
210
277
  }
211
278
  //#endregion
212
279
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.mts","names":[],"sources":["../../src/oauth2/types.ts"],"mappings":";iBACiB;EACf;EACA;EACA;;iBAGe;EACf;EACA;EACA;EACA,sBAAsB;;;;;;EAMtB,aAAa;;UAGL;EACR;EACA;EACA;EACA;EACA,OAAO,KAAK;;iBAGG;EACf;EACA;EACA;EACA;EACA,OAAO,KAAK;;iBAGG;EACf;EACA;EACA;;iBAGe;EACf;EACA;EACA;;iBAGe;EACf;EACA;EACA;EACA,OAAO;EACP,aAAa;;iBAIE;;;;;EAKf;;;;;EAMA;;;;;;;;EASA;;;;;;EAOA;;;;;;EAOA;EAEA;GAEC;;iBAGc,kBAAkB;EACjC;;YAGU;EACV;EACA;EACA;EACA;EACA;EACA;;qBAGW;YASD,oBAAoB;iBAGf;EACf;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;IACE;IACA;IACA;IACA;IACA;IACA;;EAEF;;iBAGe,SAAS;EACxB,QAAQ;EACR,MAAM;;iBAGS;;EAEf;;EAGA;;EAGA;;EAGA;;EAGA;;EAGA;;;;EAKA;;EAGA;;;;;EAMA;;EAGA;;EAGA,yBAAyB,QAAQ,iCAAiC;;EAGlE,4BAA4B,QAAQ,uBAAuB,QAAQ;;EAGnE,cAAc,OAAO,gBAAgB,QAAQ;;EAG7C,sBAAsB,QAAQ,uBAAuB,QAAQ;;EAG7D,eAAe,QAAQ,sBAAsB;EAE7C,qBACE,QAAQ,4BACL;IAAU,OAAO;IAAa,UAAU;;;iBAG9B,uBAAuB;EACtC,eAAe,qBAAqB;IAAU,OAAO;IAAa,UAAU;;;iBAG7D;;;;;EAKf;;EAGA;;EAGA;;EAGA;;EAGA;;EAYA;;EAGA;;EAGA;;iBAGe;EACf;EACA;EACA;EACA;KAAa,eAAe;;EAC5B;KACO,eAAe;aACX;KAAW,eAAe"}
1
+ {"version":3,"file":"types.d.mts","names":[],"sources":["../../src/oauth2/types.ts"],"mappings":";iBACiB;EACf;EACA;EACA;;iBAGe;EACf;;EAEA;EACA;EACA,sBAAsB;;;;;;EAMtB,aAAa;;UAGL;EACR;EACA;EACA;EACA;EACA,OAAO,KAAK;;iBAGG;EACf;EACA;;EAEA;EACA;EACA,OAAO,KAAK;;iBAGG;EACf;EACA;EACA;;iBAGe;EACf;EACA;EACA;;iBAGe;;;;;EAKf;EACA;EACA;EACA,OAAO;EACP,aAAa;;iBAIE;;;;;EAKf;;;;;EAMA;;;;;;;;EASA;;;;;;EAOA;;;;;;EAOA;EAEA;GAEC;;iBAGc,kBAAkB;EACjC;;YAGU;EACV;EACA;EACA;EACA;EACA;EACA;;;;;;;;;;;;EAYA,WAAW;;;iBAII;EACf;EACA;EACA;EACA;EACA;EACA;;;;;;;iBAQe;EACf;;qBAGW;YASD,oBAAoB;iBAGf;EACf;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;IACE;IACA;IACA;IACA;IACA;IACA;;EAEF;;iBAGe,SAAS;EACxB,QAAQ;EACR,MAAM;;iBAGS;;EAEf;;EAGA;;EAGA;;EAGA;;EAGA;;EAGA;;;;EAKA;;EAGA;;;;;EAMA;;EAGA;;EAGA,yBAAyB,QAAQ,iCAAiC;;EAGlE,4BAA4B,QAAQ,uBAAuB,QAAQ;;;;;;EAOnE,cAAc,OAAO,aAAa,SAAS,oBAAoB,QAAQ;;EAGvE,sBAAsB,QAAQ,uBAAuB,QAAQ;;EAG7D,eAAe,QAAQ,sBAAsB;EAE7C,qBACE,QAAQ,4BACL;IAAU,OAAO;IAAa,UAAU;;;iBAG9B;EACf;EACA,WAAW;;iBAGI,uBAAuB;;EAEtC,eACE,kBACA,qBACG;IAAU,OAAO;IAAa,UAAU;;;;;;;;YAQnC,0BAA0B,8BAA8B;;iBAGnD;EACf;;EAEA,eAAe;;EAEf;;EAEA;;;;;;iBAOe;EACf;;EAEA,eAAe;;;;;EAKf;;;;;;;;iBASe;;EAEf,UAAU;;EAEV,MAAM;;;;;EAKN,SAAS;;YAGC;GAAqB,cAAc;;iBAE9B;EACf;EACA;EACA;;EAEA,WAAW,yBAAyB,QAAQ"}
@@ -1 +1 @@
1
- {"version":3,"file":"types.mjs","names":[],"sources":["../../src/oauth2/types.ts"],"sourcesContent":["// reference: https://datatracker.ietf.org/doc/html/rfc7636\nexport interface PkceParameters {\n code_verifier: string;\n code_challenge: string;\n code_challenge_method: 'S256' | 'plain';\n}\n\nexport interface OAuth2AuthorizationRequest {\n state: string;\n registrationId: string;\n authorizationRequestUri: string;\n additionalParameters: PkceParameters;\n /**\n * What the host attached when the flow started (`oauth2Authorization` options), kept on the\n * server and handed back to `onAuthorized` once the callback checks out. Never sent to the\n * provider, unlike `additionalParameters`. Absent on requests stored before this field existed.\n */\n attributes?: Record<string, string>;\n}\n\ninterface CreateAuthorizationUriParams {\n state: string;\n clientId: string;\n redirectUri: string;\n scope: string[] | undefined;\n pkce?: Omit<PkceParameters, 'code_verifier'>;\n}\n\nexport interface ExchangeCodeParams {\n code: string;\n clientId: string;\n clientSecret: string;\n redirectUri: string;\n pkce?: Omit<PkceParameters, 'code_challenge' | 'code_challenge_method'>;\n}\n\nexport interface RefreshTokenParams {\n clientId: string;\n clientSecret: string;\n refreshToken: string;\n}\n\nexport interface RevokeTokenParams {\n token: string;\n clientId: string;\n clientSecret: string;\n}\n\nexport interface LoginOAuth2NativeParams {\n clientId: string;\n clientSecret: string;\n redirectUri: string;\n pkce?: PkceParameters;\n credentials: NativeCredential;\n}\n\n// reference: https://datatracker.ietf.org/doc/html/rfc6749#section-5.1\nexport interface OAuth2Token {\n /**\n * REQUIRED.\n * The access token issued by the authorization server.\n */\n access_token: string;\n\n /**\n * REQUIRED.\n * The type of the token issued as described in Section 7.1. Value is case insensitive.\n */\n token_type: 'Bearer' | 'bearer' | 'mac' | (string & {});\n\n /**\n * RECOMMENDED.\n * The lifetime in seconds of the access token. For example, the value \"3600\" denotes that the\n * access token will expire in one hour from the time the response was generated. If omitted, the\n * authorization server SHOULD provide the expiration time via other means or document the default\n * value.\n */\n expires_in?: number;\n\n /**\n * OPTIONAL.\n * The refresh token, which can be used to obtain new access tokens using the same authorization\n * grant as described in Section 6.\n */\n refresh_token?: string;\n\n /**\n * OPTIONAL.\n * If identical to the scope requested by the client; otherwise, REQUIRED. The scope of the\n * access token as described by Section 3.3.\n */\n scope?: string;\n\n id_token?: string;\n\n [key: string]: unknown;\n}\n\nexport interface OidcToken extends OAuth2Token {\n id_token: string;\n}\n\nexport type NativeCredential = {\n state?: string;\n code?: string;\n client_id?: string;\n redirect_uri?: string;\n id_token?: string;\n access_token?: string;\n};\n\nexport const OIDC_SCOPES = [\n 'openid',\n 'profile',\n 'email',\n 'phone',\n 'address',\n 'offline_access',\n] as const;\n\nexport type OidcScope = (typeof OIDC_SCOPES)[number];\n\n// https://openid.net/specs/openid-connect-core-1_0.html#StandardClaims\nexport interface StandardClaims {\n sub: string;\n name?: string;\n given_name?: string;\n family_name?: string;\n middle_name?: string;\n nickname?: string;\n preferred_username?: string;\n profile?: string;\n picture?: string;\n website?: string;\n email?: string;\n email_verified?: boolean;\n gender?: 'female' | 'male' | (string & {});\n birthdate?: string; // ISO 8601-1 [ISO8601‑1] YYYY-MM-DD format.\n zoneinfo?: string; // IANA Time Zone Database [IANA.time‑zones]\n locale?: string; // BCP47 [RFC5646] language tag.\n phone_number?: string; // E.164\n phone_number_verified?: boolean;\n address?: {\n formatted: string;\n street_address: string;\n locality: string;\n region: string;\n postal_code: string;\n country: string;\n }; // [RFC8259] JSON object\n updated_at?: number;\n}\n\nexport interface UserInfo<T = unknown> {\n claims: StandardClaims;\n data: T;\n}\n\nexport interface Provider {\n /** Authorization URI for the provider. */\n authorizationUri: string;\n\n /** Token URI for the provider. */\n tokenUri: string;\n\n /** Token revoke URI for the provider. */\n tokenRevokeUri?: string;\n\n /** Token refresh URI for the provider. */\n tokenRefreshUri?: string;\n\n /** User info URI for the provider. */\n userInfoUri?: string;\n\n /** User info authentication method for the provider. */\n userInfoAuthenticationMethod?: string;\n\n /**\n * Name of the attribute that will be used to extract the username from the call to 'userInfoUri'.\n * */\n userNameAttribute?: string;\n\n /** JWK set URI for the provider */\n jwkSetUri?: string;\n\n /**\n * URI that can either be an OpenID Connect discovery endpoint or an OAuth 2.0 Authorization\n * Server Metadata endpoint defined by RFC 8414.\n * */\n issuerUri?: string;\n\n /** Default scopes for the provider. */\n defaultScope: string[];\n\n /** step 1: generate authorization uri and redirect user to it */\n createAuthorizationUri: (params: CreateAuthorizationUriParams) => URL;\n\n /** step 2: exchange code for token */\n exchangeAuthorizationCode: (params: ExchangeCodeParams) => Promise<OAuth2Token>;\n\n /** step 3: get user info */\n getUserInfo: (token: OAuth2Token) => Promise<UserInfo>;\n\n /** others: refresh access token */\n refreshAccessToken?: (params: RefreshTokenParams) => Promise<OAuth2Token>;\n\n /** others: revoke token */\n revokeToken?: (params: RevokeTokenParams) => Promise<void>;\n\n loginOAuth2Native?: (\n params: LoginOAuth2NativeParams\n ) => Promise<{ token: OAuth2Token; userInfo: UserInfo }>;\n}\n\nexport interface OneTapProvider extends Provider {\n getTokenInfo: (id_token: string) => Promise<{ token: OAuth2Token; userInfo: UserInfo }>;\n}\n\nexport interface Registration {\n /**\n * Reference to the OAuth 2.0 provider to use. May reference an element from the 'provider'\n * property or used one of the commonly used providers (google, github, facebook, okta).\n * */\n provider?: string;\n\n /** Client ID for the registration. */\n clientId: string;\n\n /** Client secret of the registration. */\n clientSecret: string;\n\n /** Client authentication method. May be left blank when using a pre-defined provider. */\n clientAuthenticationMethod?: string;\n\n /** Authorization grant type. May be left blank when using a pre-defined provider. */\n authorizationGrantType?:\n | 'authorization_code' // default\n | 'client_credentials'\n | 'device_code'\n | 'jwt_bearer'\n // Deprecated. The latest OAuth 2.0 Security Best Current Practice disallows the use of the\n // Resource Owner Password Credentials grant.\n | 'password'\n | 'refresh_token'\n | 'token_exchange';\n\n /** Redirect URI. May be left blank when using a pre-defined provider. */\n redirectUri?: string;\n\n /** Authorization scopes. When left blank the provider's default scopes, if any, will be used. */\n scope?: string[];\n\n /** Client name. May be left blank when using a pre-defined provider. */\n clientName?: string;\n}\n\nexport interface OAuth2ClientConfig {\n baseUri: string;\n errorUri: string;\n successUri: string;\n provider: { [name: string]: Provider | undefined };\n registration:\n | { [name: string]: Registration | undefined }\n | (() => Promise<{ [name: string]: Registration | undefined }>);\n}\n"],"mappings":";AA+GA,MAAa,cAAc;CACzB;CACA;CACA;CACA;CACA;CACA;AACF"}
1
+ {"version":3,"file":"types.mjs","names":[],"sources":["../../src/oauth2/types.ts"],"sourcesContent":["// reference: https://datatracker.ietf.org/doc/html/rfc7636\nexport interface PkceParameters {\n code_verifier: string;\n code_challenge: string;\n code_challenge_method: 'S256' | 'plain';\n}\n\nexport interface OAuth2AuthorizationRequest {\n state: string;\n /** Key of the provider in `OAuth2ClientConfig.providers` the flow was started for. */\n provider: string;\n authorizationRequestUri: string;\n additionalParameters: PkceParameters;\n /**\n * What the host attached when the flow started (`oauth2Authorization` options), kept on the\n * server and handed back to `onAuthorized` once the callback checks out. Never sent to the\n * provider, unlike `additionalParameters`. Absent on requests stored before this field existed.\n */\n attributes?: Record<string, string>;\n}\n\ninterface CreateAuthorizationUriParams {\n state: string;\n clientId: string;\n redirectUri: string;\n scope: string[] | undefined;\n pkce?: Omit<PkceParameters, 'code_verifier'>;\n}\n\nexport interface ExchangeCodeParams {\n code: string;\n clientId: string;\n /** Absent for public clients (Google's installed-app clients, PKCE-only clients). */\n clientSecret?: string;\n redirectUri: string;\n pkce?: Omit<PkceParameters, 'code_challenge' | 'code_challenge_method'>;\n}\n\nexport interface RefreshTokenParams {\n clientId: string;\n clientSecret?: string;\n refreshToken: string;\n}\n\nexport interface RevokeTokenParams {\n token: string;\n clientId: string;\n clientSecret?: string;\n}\n\nexport interface LoginOAuth2NativeParams {\n /**\n * The configured client the app signs in as (its `client_id`, or the provider's default native\n * client). Id tokens must be issued to it: it is the only audience accepted.\n */\n clientId: string;\n clientSecret?: string;\n redirectUri: string;\n pkce?: PkceParameters;\n credentials: NativeCredential;\n}\n\n// reference: https://datatracker.ietf.org/doc/html/rfc6749#section-5.1\nexport interface OAuth2Token {\n /**\n * REQUIRED.\n * The access token issued by the authorization server.\n */\n access_token: string;\n\n /**\n * REQUIRED.\n * The type of the token issued as described in Section 7.1. Value is case insensitive.\n */\n token_type: 'Bearer' | 'bearer' | 'mac' | (string & {});\n\n /**\n * RECOMMENDED.\n * The lifetime in seconds of the access token. For example, the value \"3600\" denotes that the\n * access token will expire in one hour from the time the response was generated. If omitted, the\n * authorization server SHOULD provide the expiration time via other means or document the default\n * value.\n */\n expires_in?: number;\n\n /**\n * OPTIONAL.\n * The refresh token, which can be used to obtain new access tokens using the same authorization\n * grant as described in Section 6.\n */\n refresh_token?: string;\n\n /**\n * OPTIONAL.\n * If identical to the scope requested by the client; otherwise, REQUIRED. The scope of the\n * access token as described by Section 3.3.\n */\n scope?: string;\n\n id_token?: string;\n\n [key: string]: unknown;\n}\n\nexport interface OidcToken extends OAuth2Token {\n id_token: string;\n}\n\nexport type NativeCredential = {\n state?: string;\n code?: string;\n client_id?: string;\n redirect_uri?: string;\n id_token?: string;\n access_token?: string;\n /**\n * The user's name as the platform hands it to the app, for providers whose id token carries none\n * (Apple sends it on the first authorization only): iOS\n * `ASAuthorizationAppleIDCredential.fullName`, expo-apple-authentication's `credential.fullName`.\n * The snake_case fields above are OAuth / OIDC protocol parameters; this one is not, it is the\n * platform's object passed through unchanged, so it keeps the platform's own name and apps send\n * `fullName: credential.fullName` as is. Unsigned client input: the provider cleans each part and\n * ignores anything that is not a string. Parts with a standard claim become `given_name`,\n * `family_name`, `middle_name` and `nickname`; `namePrefix` / `nameSuffix` have none and are kept\n * in `userInfo.data.fullName` only.\n */\n fullName?: PersonNameComponents;\n};\n\n/** iOS `PersonNameComponents` as JSON; every part may be missing or `null`. */\nexport interface PersonNameComponents {\n givenName?: string | null;\n familyName?: string | null;\n middleName?: string | null;\n namePrefix?: string | null;\n nameSuffix?: string | null;\n nickname?: string | null;\n}\n\n/**\n * Fields of the authorization response besides `code` and `state` that a provider uses to fill in\n * the user info: Apple posts the user's name as `user` (JSON) with the first authorization only,\n * since its id token never carries one. Unsigned, so treated as untrusted input.\n */\nexport interface AuthorizationResponse {\n user?: string;\n}\n\nexport const OIDC_SCOPES = [\n 'openid',\n 'profile',\n 'email',\n 'phone',\n 'address',\n 'offline_access',\n] as const;\n\nexport type OidcScope = (typeof OIDC_SCOPES)[number];\n\n// https://openid.net/specs/openid-connect-core-1_0.html#StandardClaims\nexport interface StandardClaims {\n sub: string;\n name?: string;\n given_name?: string;\n family_name?: string;\n middle_name?: string;\n nickname?: string;\n preferred_username?: string;\n profile?: string;\n picture?: string;\n website?: string;\n email?: string;\n email_verified?: boolean;\n gender?: 'female' | 'male' | (string & {});\n birthdate?: string; // ISO 8601-1 [ISO8601‑1] YYYY-MM-DD format.\n zoneinfo?: string; // IANA Time Zone Database [IANA.time‑zones]\n locale?: string; // BCP47 [RFC5646] language tag.\n phone_number?: string; // E.164\n phone_number_verified?: boolean;\n address?: {\n formatted: string;\n street_address: string;\n locality: string;\n region: string;\n postal_code: string;\n country: string;\n }; // [RFC8259] JSON object\n updated_at?: number;\n}\n\nexport interface UserInfo<T = unknown> {\n claims: StandardClaims;\n data: T;\n}\n\nexport interface Provider {\n /** Authorization URI for the provider. */\n authorizationUri: string;\n\n /** Token URI for the provider. */\n tokenUri: string;\n\n /** Token revoke URI for the provider. */\n tokenRevokeUri?: string;\n\n /** Token refresh URI for the provider. */\n tokenRefreshUri?: string;\n\n /** User info URI for the provider. */\n userInfoUri?: string;\n\n /** User info authentication method for the provider. */\n userInfoAuthenticationMethod?: string;\n\n /**\n * Name of the attribute that will be used to extract the username from the call to 'userInfoUri'.\n * */\n userNameAttribute?: string;\n\n /** JWK set URI for the provider */\n jwkSetUri?: string;\n\n /**\n * URI that can either be an OpenID Connect discovery endpoint or an OAuth 2.0 Authorization\n * Server Metadata endpoint defined by RFC 8414.\n * */\n issuerUri?: string;\n\n /** Default scopes for the provider. */\n defaultScope: string[];\n\n /** step 1: generate authorization uri and redirect user to it */\n createAuthorizationUri: (params: CreateAuthorizationUriParams) => URL;\n\n /** step 2: exchange code for token */\n exchangeAuthorizationCode: (params: ExchangeCodeParams) => Promise<OAuth2Token>;\n\n /**\n * step 3: get user info. `context.clientId` is the client the token was issued to, the only\n * audience an id token may carry; `context.response` holds what the authorization response\n * carried besides the code, for the providers that send user data there (Apple).\n */\n getUserInfo: (token: OAuth2Token, context: UserInfoContext) => Promise<UserInfo>;\n\n /** others: refresh access token */\n refreshAccessToken?: (params: RefreshTokenParams) => Promise<OAuth2Token>;\n\n /** others: revoke token */\n revokeToken?: (params: RevokeTokenParams) => Promise<void>;\n\n loginOAuth2Native?: (\n params: LoginOAuth2NativeParams\n ) => Promise<{ token: OAuth2Token; userInfo: UserInfo }>;\n}\n\nexport interface UserInfoContext {\n clientId: string;\n response?: AuthorizationResponse;\n}\n\nexport interface OneTapProvider extends Provider {\n /** Verifies a One Tap / FedCM credential, which must be issued to `clientId` (the web client). */\n getTokenInfo: (\n id_token: string,\n clientId: string\n ) => Promise<{ token: OAuth2Token; userInfo: UserInfo }>;\n}\n\n/**\n * A client secret: a fixed string, or a function minting one for the client id it is called with\n * (Sign in with Apple's signed JWT, see `createAppleClientSecret`), called on every use so it can\n * cache and renew on its own.\n */\nexport type ClientSecret = string | ((clientId: string) => string | Promise<string>);\n\n/** The client a provider's server-side flows sign in as: the redirect flow and Google One Tap. */\nexport interface WebClient {\n clientId: string;\n /** Absent for a public client. */\n clientSecret?: ClientSecret;\n /** Default: `${baseUri}/login/oauth2/code/<provider key>`. */\n redirectUri?: string;\n /** Authorization scopes. Default: the provider's `defaultScope`. */\n scope?: string[];\n}\n\n/**\n * A client an app signs in as on the device (an iOS bundle id, a Google iOS / Android client) and\n * whose code or id token it posts to the native login route.\n */\nexport interface NativeClient {\n clientId: string;\n /** Absent for a public client (Google's installed-app clients have none). */\n clientSecret?: ClientSecret;\n /**\n * Redirect URI sent with the code exchange when the app sends no `redirect_uri` of its own.\n * Default: `${baseUri}/login/oauth2/code/<provider key>`.\n */\n redirectUri?: string;\n}\n\n/**\n * One identity source: every user it signs in has a `sub` unique within it, whichever client they\n * came through. The key in `OAuth2ClientConfig.providers` names it in the routes and in\n * `onAuthorized`. Two keys may share an implementation (two Google Cloud projects, one Okta per\n * tenant) when their subjects are separate namespaces.\n */\nexport interface ProviderConfig {\n /** The implementation: `apple`, `google`, `github`, ... from `@shware/security/oauth2/provider`. */\n provider: Provider;\n /** The redirect flow's and One Tap's client. Required by those flows. */\n web?: WebClient;\n /**\n * Clients the native login accepts besides `web`. An app names its client with `client_id`;\n * without one, the only native client is used, or `web` when there is none.\n */\n native?: NativeClient[];\n}\n\nexport type ProvidersConfig = { [key: string]: ProviderConfig | undefined };\n\nexport interface OAuth2ClientConfig {\n baseUri: string;\n errorUri: string;\n successUri: string;\n /** Providers by key; a function is called per request, for secrets read at request time. */\n providers: ProvidersConfig | (() => Promise<ProvidersConfig>);\n}\n"],"mappings":";AAoJA,MAAa,cAAc;CACzB;CACA;CACA;CACA;CACA;CACA;AACF"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shware/security",
3
- "version": "4.0.0",
3
+ "version": "5.0.0",
4
4
  "private": false,
5
5
  "repository": {
6
6
  "type": "git",