@crossauth/sveltekit 0.0.2

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.
@@ -0,0 +1,406 @@
1
+ import { OAuthClientStorage, KeyStorage, OAuthAuthorizationServer, Authenticator, OAuthAuthorizationServerOptions, DoubleSubmitCsrfTokenOptions } from '@crossauth/backend';
2
+ import { SvelteKitServer } from './sveltekitserver';
3
+ import { OpenIdConfiguration, User } from '@crossauth/common';
4
+ import { RequestEvent } from '@sveltejs/kit';
5
+
6
+ /**
7
+ * Query parameters for the `authorize` request.
8
+ */
9
+ export interface AuthorizeQueryType {
10
+ response_type: string;
11
+ client_id: string;
12
+ redirect_uri: string;
13
+ scope?: string;
14
+ state: string;
15
+ code_challenge?: string;
16
+ code_challenge_method?: string;
17
+ }
18
+ export interface ReturnBase {
19
+ ok: boolean;
20
+ error?: string;
21
+ error_description?: string;
22
+ }
23
+ /**
24
+ * Return type for {@link SvelteKitUserEndpoints.verifyEmail}
25
+ * {@link SvelteKitUserEndpoints.verifyEmailEndpoint} action.
26
+ *
27
+ * See class documentation for {@link SvelteKitUserEndpoints} for more details.
28
+ */
29
+ export interface AuthorizePageData extends ReturnBase {
30
+ authorized?: {
31
+ code: string;
32
+ state: string;
33
+ };
34
+ authorizationNeeded?: {
35
+ user: User;
36
+ response_type: string;
37
+ client_id: string;
38
+ client_name: string;
39
+ redirect_uri: string;
40
+ scope?: string;
41
+ scopes?: string[];
42
+ state: string;
43
+ code_challenge?: string;
44
+ code_challenge_method?: string;
45
+ csrfToken?: string;
46
+ };
47
+ user?: User;
48
+ csrfToken?: string;
49
+ }
50
+ export interface AuthorizeFormData extends ReturnBase {
51
+ formData?: {
52
+ [key: string]: string;
53
+ };
54
+ }
55
+ export interface DevicePageData extends ReturnBase {
56
+ authorizationNeeded?: {
57
+ user: User;
58
+ client_id: string;
59
+ client_name: string;
60
+ scope?: string;
61
+ scopes?: string[];
62
+ csrfToken?: string;
63
+ };
64
+ completed: boolean;
65
+ retryAllowed: boolean;
66
+ user?: User;
67
+ csrfToken?: string;
68
+ ok: boolean;
69
+ error?: string;
70
+ error_description?: string;
71
+ user_code?: string;
72
+ }
73
+ export interface DeviceFormData extends ReturnBase {
74
+ authorizationNeeded?: {
75
+ user: User;
76
+ client_id: string;
77
+ client_name: string;
78
+ scope?: string;
79
+ scopes?: string[];
80
+ csrfToken?: string;
81
+ };
82
+ completed: boolean;
83
+ retryAllowed: boolean;
84
+ user?: User;
85
+ csrfToken?: string;
86
+ ok: boolean;
87
+ error?: string;
88
+ error_description?: string;
89
+ user_code?: string;
90
+ }
91
+ /**
92
+ * The body parameters for the `mfa/challenge` endpoint.
93
+ */
94
+ export interface MfaChallengeBodyType {
95
+ client_id: string;
96
+ client_secret?: string;
97
+ challenge_type: string;
98
+ mfa_token: string;
99
+ authenticator_id: string;
100
+ }
101
+ export interface MfaChallengeReturn {
102
+ challenge_type?: string;
103
+ oob_code?: string;
104
+ binding_method?: string;
105
+ error?: string;
106
+ error_description?: string;
107
+ }
108
+ /**
109
+ * Options for {@link SvelteKitAuthorizationServer}
110
+ */
111
+ export interface SvelteKitAuthorizationServerOptions extends OAuthAuthorizationServerOptions {
112
+ /**
113
+ * The login URL (provided by {@link SvelteKitSessionServer}). Default `/login`
114
+ */
115
+ loginUrl?: string;
116
+ /**
117
+ * How to send the refresh token.
118
+ * - `json` sent in the JSON response as per the OAuth specification
119
+ * - `cookie` sent as a cookie called `refreshTokenCookieName`.
120
+ * - `both` both of the above
121
+ * Default `json`
122
+ */
123
+ refreshTokenType?: "json" | "cookie" | "both";
124
+ /**
125
+ * If `refreshTokenType` is `cookie` or `both`, this will be the cookie
126
+ * name. Default `CROSSAUTH_REFRESH_TOKEN`
127
+ */
128
+ refreshTokenCookieName?: string;
129
+ /**
130
+ * Domain to set when sending a refresh token cookie.
131
+ * Only used if `refreshTokenType` is not `json`
132
+ */
133
+ refreshTokenCookieDomain?: string | undefined;
134
+ /**
135
+ * Whether to set `httpOnly` when sending a refresh token cookie.
136
+ * Only used if `refreshTokenType` is not `json`
137
+ */
138
+ refreshTokenCookieHttpOnly?: boolean;
139
+ /**
140
+ * Path to set when sending a refresh token cookie.
141
+ * Only used if `refreshTokenType` is not `json`.
142
+ *
143
+ * Default "/".
144
+ */
145
+ refreshTokenCookiePath?: string;
146
+ /**
147
+ * Whether to set the `secure` flag when sending a refresh token cookie.
148
+ * Only used if `refreshTokenType` is not `json`
149
+ */
150
+ refreshTokenCookieSecure?: boolean;
151
+ /**
152
+ * SameSite value to set when sending a refresh token cookie.
153
+ * Only used if `refreshTokenType` is not `json`
154
+ */
155
+ refreshTokenCookieSameSite?: boolean | "lax" | "strict" | "none" | undefined;
156
+ /** options for csrf cookie manager */
157
+ doubleSubmitCookieOptions?: DoubleSubmitCsrfTokenOptions;
158
+ /**
159
+ * Set this to the route where you create your authorize endpoint.
160
+ *
161
+ * The default is '/oauth/authozize`
162
+ */
163
+ authorizeEndpointUrl?: string;
164
+ /**
165
+ * Set this to the route where you create your authorize endpoint.
166
+ *
167
+ * The default is '/oauth/token`
168
+ */
169
+ tokenEndpointUrl?: string;
170
+ /**
171
+ * Set this to the route where you create your jwks endpoint.
172
+ *
173
+ * The default is '/oauth/jwks`
174
+ */
175
+ jwksEndpoint?: string;
176
+ /** Pass the Sveltekit redirect function */
177
+ redirect?: any;
178
+ /** Pass the Sveltekit error function */
179
+ error?: any;
180
+ }
181
+ /**
182
+ * This class implements an OAuth authorization server, serving endpoints
183
+ * with SvelteKit.
184
+ *
185
+ * You shouldn't have to instantiate this directly. It is instantiated
186
+ * by {@link SvelteKitServer} if you enable the authorization server there.
187
+ *
188
+ * **Endpoints**
189
+ *
190
+ * | Name | Description | PageData (returned by load) or JSON returned by get/post | ActionData (return by actions) | Form fields expected by actions or post/get input data |
191
+ * | --------------------------- | ---------------------------------------------------------- | ---------------------------------------------------------------------------- | ---------------------------------------------------------------- | --------------------------------------------------------------- |
192
+ * | baseEndpoint | This PageData is returned by all endpoints' load function. | - `user` logged in {@link @crossauth/common!User} | *Not provided* | |
193
+ * | | | - `csrfToken` CSRF token if enabled | | | | loginPage |
194
+ * | --------------------------- | ---------------------------------------------------------- | ---------------------------------------------------------------------------- | ---------------------------------------------------------------- | --------------------------------------------------------------- |
195
+ * | oidcConfigurationEndpoint | Use this as your `.well-known/openid-configuration`. | `get`: | | |
196
+ * | | | - see {@link @crossauth/backend!OAuthAuthorizationServer.oidcConfiguration} | | |
197
+ * | --------------------------- | ---------------------------------------------------------- | ---------------------------------------------------------------------------- | ---------------------------------------------------------------- | --------------------------------------------------------------- |
198
+ * | jwksGetEndpoint | Use this as your `jwks` endpoint. | `get`: | | |
199
+ * | | | - see {@link @crossauth/backend!OAuthAuthorizationServer.jwks} | | |
200
+ * | --------------------------- | ---------------------------------------------------------- | ---------------------------------------------------------------------------- | ---------------------------------------------------------------- | --------------------------------------------------------------- |
201
+ * | getCsrfTokenEndpoint | Sends a CSRF token for use when refresh token is a cookie | `get`: | | |
202
+ * | | | - `ok` (true or false) | | |
203
+ * | | | - `csrfToken` | | |
204
+ * | | | - `error` | | |
205
+ * | | | - `error_description` | | |
206
+ * | --------------------------- | ---------------------------------------------------------- | ---------------------------------------------------------------------------- | ---------------------------------------------------------------- | --------------------------------------------------------------- |
207
+ * | authorizeEndpoint | The OAuth `authorize` endpoint | `load`: | `default`: | `authorized` true if the user clicks authorized |
208
+ * | | | - `succcess` (true or false) | - `ok`: true or false | `response_type` OAuth response type (take from PageData) |
209
+ * | | | - `authorizationNeeded`: | - `formData`: fata submitted from in the form | `client_id` take from PageData |
210
+ * | | | - `user`: the user object | - `error` an OAuth error type | `redirect_uri` take from PageData |
211
+ * | | | - `response_type`: OAuth response type | - `error_description` text error description | `scope` take from PageData |
212
+ * | | | - `client_id`: | | `state` take from PageData |
213
+ * | | | - `client_name`: | | `code_challenge` take from PageData |
214
+ * | | | - `redirect_uri`: | | `code_challenge_method` take from PageData |
215
+ * | | | - `scope`: as a string | | |
216
+ * | | | - `scopes`: as an array | | |
217
+ * | | | - `state`: | | |
218
+ * | | | - `code_challenge`: | | |
219
+ * | | | - `code_challenge_method`: | | |
220
+ * | | | - `csrfToken`: | | |
221
+ * | | | - `error` | | |
222
+ * | | | - `error_description` | | |
223
+ * | | | See OAuth definition for more detials. | | |
224
+ * | --------------------------- | ---------------------------------------------------------- | ---------------------------------------------------------------------------- | ---------------------------------------------------------------- | --------------------------------------------------------------- |
225
+ * | tokenEndpoint | The OAuth `token` endpoint | `post`: | | See OAuth definition of `token` endpoint |
226
+ * | | | - See OAuth definition of `token` endpoint | | |
227
+ * | --------------------------- | ---------------------------------------------------------- | ---------------------------------------------------------------------------- | ---------------------------------------------------------------- | --------------------------------------------------------------- |
228
+ * | mfaAuthenticatorsEndpoint | For the Auth0 Password MFA authenticators | `get`: | | See OAuth definition of `token` endpoint |
229
+ * | | | - See Auth0 Password MFA documentation | | |
230
+ * | | | `post`: | | |
231
+ * | | | - See Auth0 Password MFA documentation | | See OAuth definition of `token` endpoint |
232
+ * | --------------------------- | ---------------------------------------------------------- | ---------------------------------------------------------------------------- | ---------------------------------------------------------------- | --------------------------------------------------------------- |
233
+ * | mfaChallengeEndpoint | For the Auth0 Password MFA challenge | `post`: | | See OAuth definition of `token` endpoint |
234
+ * | | | - See Auth0 Password MFA documentation | | |
235
+ * | --------------------------- | ---------------------------------------------------------- | ---------------------------------------------------------------------------- | ---------------------------------------------------------------- | --------------------------------------------------------------- |
236
+ * | deviceAuthorizationEndpoint | Starts the device flow (for the device) | `post`: | | `client_id` client ID |
237
+ * | | | - `ok` true or false | | `client_secret` if the client is confidential |
238
+ * | | | - `error` if there was an error | | `scope` optional |
239
+ * | | | - `error_description` if there was an error | | |
240
+ * | --------------------------- | ---------------------------------------------------------- | ---------------------------------------------------------------------------- | ---------------------------------------------------------------- | --------------------------------------------------------------- |
241
+ * | deviceEndpoint | Device flow - authorization endpoint on other device | `load`: | `authorize`: to authorize scopes (call after `userCode`) | `user_code` query param for GET, form field for POST. Optional |
242
+ * | | | See {@link DevicePageData} | See {@link DeviceFormData} | If not provided, user will be prompted |
243
+ * | | | | `userCode` to submit the user code | `authorize`: `client_id`, `user_code`, `authorized` |
244
+ * | --------------------------- | ---------------------------------------------------------- | ---------------------------------------------------------------------------- | ---------------------------------------------------------------- | --------------------------------------------------------------- |
245
+ *
246
+ */
247
+ export declare class SvelteKitAuthorizationServer {
248
+ /** The underlying framework-independent authorization server */
249
+ readonly authServer: OAuthAuthorizationServer;
250
+ private svelteKitServer;
251
+ private loginUrl;
252
+ private clientStorage;
253
+ private refreshTokenType;
254
+ private refreshTokenCookieName;
255
+ private refreshTokenCookieDomain;
256
+ private refreshTokenCookieHttpOnly;
257
+ private refreshTokenCookiePath;
258
+ private refreshTokenCookieSecure;
259
+ private refreshTokenCookieSameSite;
260
+ private csrfTokens;
261
+ private authorizeEndpointUrl;
262
+ private tokenEndpointUrl;
263
+ private jwksEndpointUrl;
264
+ readonly redirect: any;
265
+ readonly error: any;
266
+ /**
267
+ * Constructor
268
+ * @param svelteKitServer the SvelteKit server this belongs to
269
+ * @param clientStorage where OAuth clients are stored
270
+ * @param keyStorage where refresh tokens, authorization cods, etc are temporarily stored
271
+ * @param authenticators The authenticators (factor1 and factor2) to enable
272
+ * for the password flow
273
+ * @param options see {@link SvelteKitAuthorizationServerOptions}
274
+ */
275
+ constructor(svelteKitServer: SvelteKitServer, clientStorage: OAuthClientStorage, keyStorage: KeyStorage, authenticators?: {
276
+ [key: string]: Authenticator;
277
+ }, options?: SvelteKitAuthorizationServerOptions);
278
+ /**
279
+ * Returns this server's OIDC configuration. Just wraps
280
+ * {@link @crossauth/backend!OAuthAuthorizationServer.oidcConfiguration}
281
+ * @returns An {@link @crossauth/common!OpenIdConfiguration} object
282
+ */
283
+ oidcConfiguration(): OpenIdConfiguration;
284
+ /**
285
+ * Either returns an error or redirects with throw
286
+ */
287
+ private authorize;
288
+ /**
289
+ * Creates and returns a signed CSRF token based on the session ID
290
+ *
291
+ * This is for the situation when the refresh token is sent as a cookie.
292
+ * When this happens, we need CSRF protection on it.
293
+ *
294
+ * @returns a CSRF cookie and value to put in the form or CSRF header
295
+ */
296
+ private createCsrfToken;
297
+ private setRefreshTokenCookie;
298
+ private requireGetParam;
299
+ private requireBodyParam;
300
+ private getAuthorizeQuery;
301
+ private getMfaChallengeQuery;
302
+ private mfaAuthenticators;
303
+ private mfaChallenge;
304
+ private getClientIdAndSecret;
305
+ private applyUserCode;
306
+ /**
307
+ * Fields that are returned by all endpoint load methods
308
+ *
309
+ * See class description
310
+ * @param event the SvelteKit event
311
+ * @returns an object with:
312
+ * - `user` the `User` object from `event.locals.user`
313
+ * - `csrfToken` the CSRF token from `event.locals.csrfToken`
314
+ */
315
+ baseEndpoint(event: RequestEvent): {
316
+ user: User | undefined;
317
+ csrfToken: string | undefined;
318
+ };
319
+ /**
320
+ * `get` function for the oidcConfiguration endpoint.
321
+ *
322
+ * See class description for details.
323
+ */
324
+ readonly oidcConfigurationEndpoint: {
325
+ get: (_event: RequestEvent) => Promise<Response>;
326
+ };
327
+ /**
328
+ * `get` function for the jwks endpoint.
329
+ *
330
+ * See class description for details.
331
+ */
332
+ readonly jwksGetEndpoint: {
333
+ get: (_event: RequestEvent) => Promise<Response>;
334
+ };
335
+ /**
336
+ * `get` function for the csrfToken endpoint.
337
+ *
338
+ * See class description for details. Not needed if you disable CSRF
339
+ * protection to rely on Sveltekit's.
340
+ */
341
+ readonly getCsrfTokenEndpoint: {
342
+ get: (event: RequestEvent) => Promise<Response>;
343
+ };
344
+ /**
345
+ * `load` and `actions` functions for the authorize endpoint.
346
+ *
347
+ * See class description for details. Not needed if you disable CSRF
348
+ * protection to rely on Sveltekit's.
349
+ */
350
+ readonly authorizeEndpoint: {
351
+ load: (event: RequestEvent) => Promise<AuthorizePageData>;
352
+ actions: {
353
+ default: (event: RequestEvent) => Promise<AuthorizeFormData>;
354
+ };
355
+ };
356
+ /**
357
+ * `post` function for the token endpoint.
358
+ *
359
+ * See class description for details. Not needed if you disable CSRF
360
+ * protection to rely on Sveltekit's.
361
+ */
362
+ readonly tokenEndpoint: {
363
+ post: (event: RequestEvent) => Promise<Response>;
364
+ };
365
+ /**
366
+ * `get` and `post` functions for the mfa/authenticators endpoint.
367
+ *
368
+ * See class description for details. Not needed if you disable CSRF
369
+ * protection to rely on Sveltekit's.
370
+ */
371
+ readonly mfaAuthenticatorsEndpoint: {
372
+ get: (event: RequestEvent) => Promise<Response>;
373
+ post: (event: RequestEvent) => Promise<Response>;
374
+ };
375
+ /**
376
+ * `post` function for the mfa/challenge endpoint.
377
+ *
378
+ * See class description for details. Not needed if you disable CSRF
379
+ * protection to rely on Sveltekit's.
380
+ */
381
+ readonly mfaChallengeEndpoint: {
382
+ post: (event: RequestEvent) => Promise<Response>;
383
+ };
384
+ /**
385
+ * `post` function for the device_authorization endpoint.
386
+ *
387
+ * See class description for details. Not needed if you disable CSRF
388
+ * protection to rely on Sveltekit's.
389
+ */
390
+ readonly deviceAuthorizationEndpoint: {
391
+ post: (event: RequestEvent) => Promise<Response>;
392
+ };
393
+ /**
394
+ * `load` and `actions` functions for the authorize endpoint.
395
+ *
396
+ * See class description for details. Not needed if you disable CSRF
397
+ * protection to rely on Sveltekit's.
398
+ */
399
+ readonly deviceEndpoint: {
400
+ load: (event: RequestEvent) => Promise<DevicePageData>;
401
+ actions: {
402
+ userCode: (event: RequestEvent) => Promise<DeviceFormData>;
403
+ authorize: (event: RequestEvent) => Promise<DeviceFormData>;
404
+ };
405
+ };
406
+ }
@@ -0,0 +1,101 @@
1
+ import { RequestEvent, MaybePromise } from '@sveltejs/kit';
2
+ import { User } from '@crossauth/common';
3
+ import { OAuthResourceServer, UserStorage, OAuthResourceServerOptions, OAuthTokenConsumer } from '@crossauth/backend';
4
+
5
+ /**
6
+ * Options for {@link SvelteKitOAuthResourceServer}
7
+ */
8
+ export interface SvelteKitOAuthResourceServerOptions extends OAuthResourceServerOptions {
9
+ /** If you set this and your access tokens have a user (`sub` claim),
10
+ * the `user` field in the request will be populated with a valid
11
+ * access token,
12
+ */
13
+ userStorage?: UserStorage;
14
+ /**
15
+ * If you enabled `protectedEndpoints` in
16
+ * {@link FastifyOAuthResourceServer.constructor}
17
+ * and the access token is invalid, a 401 reply will be sent before
18
+ * your endpoint is hit. This will be the body, Default {}.
19
+ */
20
+ errorBody?: {
21
+ [key: string]: any;
22
+ };
23
+ /**
24
+ * If you define this, matching resource server endpoints will return
25
+ * a status code of 401 Access Denied if the key is invalid or the
26
+ * given scopes are not present.
27
+ */
28
+ protectedEndpoints?: {
29
+ [key: string]: {
30
+ scope?: string[];
31
+ acceptSessionAuthorization?: boolean;
32
+ };
33
+ };
34
+ }
35
+ /**
36
+ * OAuth resource server.
37
+ *
38
+ * You can subclass this, simply instantiate it, or create it through
39
+ * {@link SvelteKitServer}.
40
+ *
41
+ * There are two way of using this class. If you don't set
42
+ * `protectedEndpoints` in
43
+ * {@link SvelteKitAuthResourceServer.constructor}, then in your
44
+ * protected endpoints, call {@link SvelteKitOAuthResourceServer.authorized}
45
+ * to check if the access token is valid and get any user credentials.
46
+ *
47
+ * If you do set `protectedEndpoints` in
48
+ * {@link SvelteKitOAuthResourceServer.constructor}
49
+ * then a hook is created.
50
+ * The hook
51
+ * hook will set the `accessTokenPayload`, `user` and `scope` fields
52
+ * on the event locals based on the content
53
+ * of the access token in the `Authorization` header if it is valid.
54
+ * If it is not valid it will set the `authError` and `authErrorDescription`.
55
+ * If the access token is invalid, or there is an error, a 401 or 500
56
+ * response is sent before executing your endpoint code. As per
57
+ * OAuth requirements, if the response is a 401, the WWW-Authenticate header
58
+ * is set. If a scope is required this is included in that header.
59
+ */
60
+ export declare class SvelteKitOAuthResourceServer extends OAuthResourceServer {
61
+ private userStorage?;
62
+ private errorBody;
63
+ private protectedEndpoints;
64
+ /**
65
+ * Hook to check if the user is logged in and set data in `locals`
66
+ * accordingly.
67
+ */
68
+ readonly hook?: (input: {
69
+ event: RequestEvent;
70
+ }) => MaybePromise<Response | undefined>;
71
+ /**
72
+ * Constructor
73
+ * @param tokenConsumers the token consumers, one per issuer
74
+ * @param options See {@link SvelteKitOAuthResourceServerOptions}
75
+ */
76
+ constructor(tokenConsumers: OAuthTokenConsumer[], options?: SvelteKitOAuthResourceServerOptions);
77
+ private authenticateHeader;
78
+ /**
79
+ * If there is no bearer token, returns `undefinerd`. If there is a
80
+ * bearer token and it is a valid access token, returns the token
81
+ * payload. If there was an error, returns it in OAuth form.
82
+ *
83
+ * @param event the SvelteKit request event
84
+ * @returns an object with the following fiekds
85
+ * - `authorized` : `true` or `false`
86
+ * - `tokenPayload` : the token payload if the token is valid
87
+ * - `error` : if the token is not valid
88
+ * - `error_description` : if the token is not valid
89
+ * - `user` set if `sub` is defined in the token, a userStorage has
90
+ * been defined and it matches
91
+ */
92
+ authorized(event: RequestEvent): Promise<{
93
+ authorized: boolean;
94
+ tokenPayload?: {
95
+ [key: string]: any;
96
+ };
97
+ user?: User;
98
+ error?: string;
99
+ error_description?: string;
100
+ } | undefined>;
101
+ }