@crossauth/fastify 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.
Files changed (35) hide show
  1. package/LICENSE +203 -0
  2. package/README.md +12 -0
  3. package/dist/fastifyadminclientendpoints.d.ts +149 -0
  4. package/dist/fastifyadminendpoints.d.ts +126 -0
  5. package/dist/fastifyapikey.d.ts +42 -0
  6. package/dist/fastifyoauthclient.d.ts +429 -0
  7. package/dist/fastifyoauthserver.d.ts +248 -0
  8. package/dist/fastifyresserver.d.ts +93 -0
  9. package/dist/fastifyserver.d.ts +293 -0
  10. package/dist/fastifysession.d.ts +767 -0
  11. package/dist/fastifysessionadapter.d.ts +48 -0
  12. package/dist/fastifyuserclientendpoints.d.ts +61 -0
  13. package/dist/fastifyuserendpoints.d.ts +193 -0
  14. package/dist/index.cjs +9085 -0
  15. package/dist/index.d.ts +40 -0
  16. package/dist/index.js +9085 -0
  17. package/dist/tests/admincommon.d.ts +20 -0
  18. package/dist/tests/fastifyadminapiendpoints.test.d.ts +13 -0
  19. package/dist/tests/fastifyadminclientapiendpoints.test.d.ts +13 -0
  20. package/dist/tests/fastifyadminclientendpoints.test.d.ts +13 -0
  21. package/dist/tests/fastifyadminendpoints.test.d.ts +13 -0
  22. package/dist/tests/fastifyapikeyserver.test.d.ts +13 -0
  23. package/dist/tests/fastifyapiserver.test.d.ts +11 -0
  24. package/dist/tests/fastifyapitwofactor.test.d.ts +11 -0
  25. package/dist/tests/fastifyauthserver.test.d.ts +17 -0
  26. package/dist/tests/fastifyclient.test.d.ts +1 -0
  27. package/dist/tests/fastifymfaclient.test.d.ts +4 -0
  28. package/dist/tests/fastifyresserver.test.d.ts +1 -0
  29. package/dist/tests/fastifysessionserver.test.d.ts +13 -0
  30. package/dist/tests/fastifytwofactorserver.test.d.ts +17 -0
  31. package/dist/tests/fastifyuserclientapiendpoints.test.d.ts +13 -0
  32. package/dist/tests/fastifyuserclientendpoints.test.d.ts +13 -0
  33. package/dist/tests/inmemorytestdata.d.ts +3 -0
  34. package/dist/tests/oauthcommon.d.ts +45 -0
  35. package/package.json +75 -0
@@ -0,0 +1,93 @@
1
+ import { FastifyRequest, FastifyInstance } from 'fastify';
2
+ import { Server, IncomingMessage, ServerResponse } from 'http';
3
+ import { User } from '@crossauth/common';
4
+ import { OAuthResourceServer, UserStorage, OAuthResourceServerOptions, OAuthTokenConsumer } from '@crossauth/backend';
5
+
6
+ /**
7
+ * Options for {@link FastifyOAuthResourceServer}
8
+ */
9
+ export interface FastifyOAuthResourceServerOptions extends OAuthResourceServerOptions {
10
+ /** If you set this and your access tokens have a user (`sub` claim),
11
+ * the `user` field in the request will be populated with a valid
12
+ * access token,
13
+ */
14
+ userStorage?: UserStorage;
15
+ /**
16
+ * If you enabled `protectedEndpoints` in
17
+ * {@link FastifyOAuthResourceServer.constructor}
18
+ * and the access token is invalid, a 401 reply will be sent before
19
+ * your endpoint is hit. This will be the body, Default {}.
20
+ */
21
+ errorBody?: {
22
+ [key: string]: any;
23
+ };
24
+ /**
25
+ * If you define this, matching resource server endpoints will return
26
+ * a status code of 401 Access Denied if the key is invalid or the
27
+ * given scopes are not present.
28
+ */
29
+ protectedEndpoints?: {
30
+ [key: string]: {
31
+ scope?: string[];
32
+ acceptSessionAuthorization?: boolean;
33
+ };
34
+ };
35
+ }
36
+ /**
37
+ * OAuth resource server.
38
+ *
39
+ * You can subclass this, simply instantiate it, or create it through
40
+ * {@link FastifyServer}.
41
+ *
42
+ * There are two way of using this class. If you don't set
43
+ * `protectedEndpoints` in
44
+ * {@link FastifyOAuthResourceServer.constructor}, then in your
45
+ * protected endpoints, call {@link FastifyOAuthResourceServer.authorized}
46
+ * to check if the access token is valid and get any user credentials.
47
+ *
48
+ * If you do set `protectedEndpoints` in
49
+ * {@link FastifyOAuthResourceServer.constructor}
50
+ * then a `preHandler` iscreated.
51
+ * The preHandler
52
+ * hook will set the `accessTokenPayload`, `user` and `scope` fields
53
+ * on the Fastify request object based on the content
54
+ * of the access token in the `Authorization` header if it is valid.
55
+ * If it is not valid it will set the `authError` and `authErrorDescription`.
56
+ * If the access token is invalid, or there is an error, a 401 or 500
57
+ * response is sent before executing your endpoint code. As per
58
+ * OAuth requirements, if the response is a 401, the WWW-Authenticate header
59
+ * is set. If a scope is required this is included in that header.
60
+ */
61
+ export declare class FastifyOAuthResourceServer extends OAuthResourceServer {
62
+ private userStorage?;
63
+ private protectedEndpoints;
64
+ private errorBody;
65
+ /**
66
+ * Constructor
67
+ * @param app the Fastify app
68
+ * @param tokenConsumers the token consumers, one per issuer
69
+ * @param options See {@link FastifyOAuthResourceServerOptions}
70
+ */
71
+ constructor(app: FastifyInstance<Server, IncomingMessage, ServerResponse>, tokenConsumers: OAuthTokenConsumer[], options?: FastifyOAuthResourceServerOptions);
72
+ private authenticateHeader;
73
+ /**
74
+ * If there is no bearer token, returns `undefinerd`. If there is a
75
+ * bearer token and it is a valid access token, returns the token
76
+ * payload. If there was an error, returns it in OAuth form.
77
+ * @param request the Fastify request
78
+ * @returns an objuect with the following fiekds
79
+ * - `authorized` : `true` or `false`
80
+ * - `tokenPayload` : the token payload if the token is valid
81
+ * - `error` : if the token is not valid
82
+ * - `error_description` : if the token is not valid
83
+ */
84
+ authorized(request: FastifyRequest): Promise<{
85
+ authorized: boolean;
86
+ tokenPayload?: {
87
+ [key: string]: any;
88
+ };
89
+ user?: User;
90
+ error?: string;
91
+ error_description?: string;
92
+ } | undefined>;
93
+ }
@@ -0,0 +1,293 @@
1
+ import { FastifyInstance, FastifyRequest, FastifyReply } from 'fastify';
2
+ import { Server, IncomingMessage, ServerResponse } from 'http';
3
+ import { CrossauthError, User } from '@crossauth/common';
4
+ import { KeyStorage, OAuthClientStorage } from '@crossauth/backend';
5
+ import { FastifySessionServer, FastifySessionServerOptions, CsrfBodyType } from './fastifysession';
6
+ import { FastifySessionAdapter } from './fastifysessionadapter';
7
+ import { FastifyApiKeyServerOptions } from './fastifyapikey';
8
+ import { FastifyAuthorizationServer, FastifyAuthorizationServerOptions } from './fastifyoauthserver';
9
+ import { FastifyOAuthClient, FastifyOAuthClientOptions } from './fastifyoauthclient';
10
+ import { FastifyOAuthResourceServer, FastifyOAuthResourceServerOptions } from './fastifyresserver';
11
+
12
+ export declare const ERROR_400 = "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n<html><head>\n<title>400 Bad Request</title>\n</head><body>\n<h1>400 Bad Request</h1>\n<p>The server was unable to handle your request.</p>\n</body></html>\n";
13
+ export declare const ERROR_401 = "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n<html><head>\n<title>401 Unauthorized</title>\n</head><body>\n<h1>401 Unauthorized</h1>\n<p>You are not authorized to access this URL.</p>\n</body></html>\n";
14
+ export declare const ERROR_403 = "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n<html><head>\n<title>403 Forbidden</title>\n</head><body>\n<h1>403 Forbidden</h1>\n<p>You are not authorized to make this request.</p>\n</body></html>\n";
15
+ export declare const ERROR_500 = "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n<html><head>\n<title>500 Server Error</title>\n</head><body>\n<h1>500 Error</h1>\n<p>Sorry, an unknown error has occured</p>\n</body></html>\n";
16
+ export declare const DEFAULT_ERROR: {
17
+ 400: string;
18
+ 401: string;
19
+ 500: string;
20
+ };
21
+ /**
22
+ * Options for {@link FastifyServer }.
23
+ *
24
+ * See {@link FastifyServer } constructor for description of parameters
25
+ */
26
+ export interface FastifyServerOptions extends FastifySessionServerOptions, FastifyApiKeyServerOptions, FastifyAuthorizationServerOptions, FastifyOAuthClientOptions, FastifyOAuthResourceServerOptions {
27
+ /** You can pass your own fastify instance or omit this, in which case Crossauth will create one */
28
+ app?: FastifyInstance<Server, IncomingMessage, ServerResponse>;
29
+ /** If this is passed, it is registered as a Nunjucks view folder with autoscape on */
30
+ views?: string;
31
+ isAdminFn?: (user: User) => boolean;
32
+ }
33
+ /**
34
+ * Type for the function that is called to pass an error back to the user
35
+ *
36
+ * The function is passed this instance, the request that generated the
37
+ * error, the response object for sending the respons to and the
38
+ * exception that was raised.
39
+ */
40
+ export type FastifyErrorFn = (server: FastifyServer, request: FastifyRequest, reply: FastifyReply, ce: CrossauthError) => Promise<FastifyReply>;
41
+ /**
42
+ * This class provides a complete (but without HTML files) auth backend server
43
+ * for Fastify applications
44
+ *
45
+ * If you do not pass an Fastify app to this class, it will create one.
46
+ * By default, pages are rendered
47
+ * with Nunjucks. If you prefer another renderer that is compatible with
48
+ * Fastify, create your
49
+ * own Fastify app and configure the renderer using @fastify/view.
50
+ *
51
+ * By default, all views are expected to be in a directory called `views`
52
+ * relative to the directory the
53
+ * server is started in. This can be overwritten by setting the `views` option.
54
+ *
55
+ * Note that `views`, and the Nunjucks pages are not used by the API
56
+ * endpoints (those starting in /api). These just return JSON.
57
+ *
58
+ * **Component Servers**
59
+ *
60
+ * This class contains a number of servers which don't all have to be
61
+ * created, depending on what authentication you want to support. If
62
+ * instantiated, they can work together.
63
+ *
64
+ * - `sessionServer` Session cookie management server. Uses sesion ID
65
+ * and CSRF cookies. See {@link FastifySessionServer}.
66
+ * - `sessionAdapter` If you want an OAuth client but not want to use
67
+ * Fastify's session server, you can provide your own
68
+ * with this. Won't work with auth server.
69
+ * - `oAuthAuthServer` OAuth authorization server. See
70
+ * {@link FastifyAuthorizationServer}
71
+ * - `oAuthClient` OAuth client. See {@link FastifyOAuthClient}.
72
+ * - `oAuthClients` An array of OAuthClients if you want more than one.
73
+ * Use either this or `oAuthClient` but not both.
74
+ * See {@link FastifyOAuthClient}.
75
+ * - `oAuthResServer` OAuth resource server. See
76
+ * {@link FastifyOAuthResourceServer}.
77
+ *
78
+ * There is also an API key server which is not available as a variable as
79
+ * it has no functions other than the hook it registers.
80
+ * See {@link FastifyApiKeyServer}.
81
+ *
82
+ * For a list of user-level URLs that can be enabled, and their input and output
83
+ * requirements, see {@link FastifySessionServer}. FOr a list of
84
+ * admin endpoints that can be enabled, see {@link FastifyAdminEndpoints}.
85
+ *
86
+ * **Authenticators**
87
+ *
88
+ * One and two factor authentication is supported. Authentication is provided
89
+ * by classes implementing {@link Authenticator}. They are passed as an
90
+ * object to this class, keyed on the name that appears in the user record
91
+ * as `factor1` or `factor2`.
92
+ *
93
+ * For example, if you have passwords in your user database, you can use
94
+ * {@link @crossauth/backend!LocalPasswordAuthenticator}. If this method of authentication
95
+ * is called `password` in the `factor1` field of the user record,
96
+ * pass it in the `authenticators` parameter in the constructor with a key
97
+ * of `password`.
98
+ *
99
+ */
100
+ export declare class FastifyServer {
101
+ private views;
102
+ private static isAdminFn;
103
+ /** The Fastify app, which was either passed in the constructor or
104
+ * created if none was passed in.
105
+ */
106
+ readonly app: FastifyInstance<Server, IncomingMessage, ServerResponse>;
107
+ /** See class comment */
108
+ readonly sessionServer?: FastifySessionServer;
109
+ /**
110
+ * See class comment
111
+ *
112
+ * Will be the same as `sessionServer` if that is passed instawd
113
+ */
114
+ readonly sessionAdapter?: FastifySessionAdapter;
115
+ /** See class comment */
116
+ readonly oAuthAuthServer?: FastifyAuthorizationServer;
117
+ /** See class comment */
118
+ readonly oAuthClient?: FastifyOAuthClient;
119
+ /** See class comment */
120
+ readonly oAuthClients?: FastifyOAuthClient[];
121
+ /** See class comment */
122
+ readonly oAuthResServer?: FastifyOAuthResourceServer;
123
+ /** Config for `@fastify/cors` */
124
+ private cors;
125
+ /**
126
+ * Integrates fastify session, API key and OAuth servers
127
+ * @param config object with entries as follow:
128
+ * - `session` if passed, instantiate the session server (see class
129
+ * documentation). The value is an object with a `keyStorage` field
130
+ * which must be present and should be the {@link KeyStorage} instance
131
+ * where session IDs are stored. A field called `options` whose
132
+ * value is an {@link FastifySessionServerOptions} may also be
133
+ * provided.
134
+ * - `apiKey` if passed, instantiate the session server (see class
135
+ * documentation). The value is an object with a `keyStorage` field
136
+ * which must be present and should be the {@link KeyStorage} instance
137
+ * where API keys are stored. A field called `options` whose
138
+ * value is an {@link FastifyApiKeyServerOptions} may also be
139
+ * provided.
140
+ * - `oAuthAuthServer` if passed, instantiate the session server (see class
141
+ * documentation). The value is an object with a `keyStorage` field
142
+ * which must be present and should be the {@link KeyStorage} instance
143
+ * where authorization codes are stored. This may be the same as
144
+ * the table storing session IDs or may be different. A field
145
+ * called `clientStorage` with a value of type {@link OAuthClientStorage}
146
+ * must be provided and is where OAuth client details are stored.
147
+ * A field called `options` whose
148
+ * value is an {@link FastifyAuthorizationServerOptions} may also be
149
+ * provided.
150
+ * - `oAuthClient` if present, an OAuth client will be created.
151
+ * There must be a field called `authServerBaseUrl` and is the
152
+ * bsae URL for the authorization server. When validating access
153
+ * tokens, the `iss` claim must match this.
154
+ * - `oAuthClients` if present, an array of OAuth clients will be created.
155
+ * There must be a field called `authServerBaseUrl` and is the
156
+ * bsae URL for the authorization serve for each. When validating access
157
+ * tokens, the `iss` claim must match this.
158
+ * Do not use both this and `oAuthClient`.
159
+ * - `oAuthResServer` if present. an OAuth resource server will be
160
+ * created. It has one optional field: `protectedEndpoints`. The
161
+ * value is an object whose key is a URL (relative to the base
162
+ * URL of the application). The value is an object that contains
163
+ * one optional parameter: `scope`, a string. The client/user calling
164
+ * the endpoint must have authorized this scope to call this endpoint,
165
+ * otherwise an access denied error is returned.
166
+ * @param options application-wide options of type
167
+ * {@link FastifyServerOptions}.
168
+ *
169
+ */
170
+ constructor({ session, sessionAdapter, apiKey, oAuthAuthServer, oAuthClient, oAuthClients, oAuthResServer }: {
171
+ session?: {
172
+ keyStorage: KeyStorage;
173
+ options?: FastifySessionServerOptions;
174
+ };
175
+ sessionAdapter?: FastifySessionAdapter;
176
+ apiKey?: {
177
+ keyStorage: KeyStorage;
178
+ options?: FastifyApiKeyServerOptions;
179
+ };
180
+ oAuthAuthServer?: {
181
+ clientStorage: OAuthClientStorage;
182
+ keyStorage: KeyStorage;
183
+ options?: FastifyAuthorizationServerOptions;
184
+ };
185
+ oAuthClient?: {
186
+ authServerBaseUrl: string;
187
+ options?: FastifyOAuthClientOptions;
188
+ };
189
+ oAuthClients?: {
190
+ authServerBaseUrl: string;
191
+ options?: FastifyOAuthClientOptions;
192
+ }[];
193
+ oAuthResServer?: {
194
+ options?: FastifyOAuthResourceServerOptions;
195
+ };
196
+ }, options?: FastifyServerOptions);
197
+ /**
198
+ * This is a convenience function that just wraps
199
+ * {@link FastifySessionServer.validateCsrfToken}.
200
+ * @param request the fastify request
201
+ * @returns a string of the CSRF cookie value or undefined if it
202
+ * is not valid.
203
+ */
204
+ validateCsrfToken(request: FastifyRequest<{
205
+ Body: CsrfBodyType;
206
+ }>): string | undefined;
207
+ /**
208
+ * Calls the passed error function passed if the CSRF
209
+ * token in the request is invalid.
210
+ *
211
+ * Use this to require a CSRF token in your endpoints.
212
+ *
213
+ * @param request the Fastify request
214
+ * @param reply the Fastify reply object
215
+ * @param errorFn the error function to call if the CSRF token is invalid
216
+ * @returns if no error, returns an object with `error` set to false and
217
+ * `reply` set to the passed reply object. Otherwise returns the reply
218
+ * from calling `errorFn`.
219
+ */
220
+ errorIfCsrfInvalid(request: FastifyRequest<{
221
+ Body: CsrfBodyType;
222
+ }>, reply: FastifyReply, errorFn?: FastifyErrorFn): Promise<{
223
+ reply: FastifyReply;
224
+ error: boolean;
225
+ }>;
226
+ /**
227
+ * Calls the passed error function passed if the user is not logged in.
228
+ *
229
+ * Use this to password protect endpoints.
230
+ *
231
+ * @param request the Fastify request
232
+ * @param reply the Fastify reply object
233
+ * @param errorFn the error function to call if the user is not logged in.
234
+ * @returns if no error, returns an object with `error` set to false and
235
+ * `reply` set to the passed reply object. Otherwise returns the reply
236
+ * from calling `errorFn`.
237
+ */
238
+ errorIfNotLoggedIn(request: FastifyRequest<{
239
+ Body: CsrfBodyType;
240
+ }>, reply: FastifyReply, errorFn?: FastifyErrorFn): Promise<FastifyReply | undefined>;
241
+ /**
242
+ * Sends a reply by rendering the `errorPage` if present, or a standard
243
+ * error page if it isn't.
244
+ *
245
+ * The renderer configured for the reply object is called (Nunjucks
246
+ * by default) with the following data parameters:
247
+ * - `errorCode` See {@link @crossauth/common!ErrorCode}.
248
+ * - `errorCodeName` the text version of `errorCode`.
249
+ * - `msg` the error message
250
+ * - `httpStatus` the HTTP status code.
251
+ *
252
+ * @param reply the Fastify reply object
253
+ * @param status the HTTP status code to return
254
+ * @param errorPage the error page to render.
255
+ * @param error an error message string. Ignored if `e` is defined.
256
+ * @param e optionall, an exception. This will be logged and the message
257
+ * will be sent to the error page.
258
+ * @returns the reply from rendering the error page.
259
+ *
260
+ */
261
+ static sendPageError(reply: FastifyReply, status: number, errorPage?: string, error?: string, e?: any): FastifyReply<import('fastify').RawServerDefault, IncomingMessage, ServerResponse<IncomingMessage>, import('fastify').RouteGenericInterface, unknown, import('fastify').FastifySchema, import('fastify').FastifyTypeProviderDefault, unknown>;
262
+ /**
263
+ * Creates a session ID but not associated with a user in the database.
264
+ *
265
+ * This is useful for tracking data between requests before a user
266
+ * has logged in
267
+ * @param request the Fastify request
268
+ * @param reply the Fastify reply
269
+ * @param data data to put in the sesion's `data` field.
270
+ * @returns the new session cookie value.
271
+ */
272
+ createAnonymousSession(request: FastifyRequest, reply: FastifyReply, data?: {
273
+ [key: string]: any;
274
+ }): Promise<string>;
275
+ /**
276
+ * Calls the `isAdminFn` passed during construction.
277
+ * @param user the user to check
278
+ * @returns true if the passed user is an admin, false otherwise.
279
+ */
280
+ static isAdmin(user: User): boolean;
281
+ /**
282
+ * Starts the Fastify app on the given port.
283
+ * @param port the port to listen on
284
+ */
285
+ start(port?: number): void;
286
+ /**
287
+ * Returns a hash of the session ID. Used for logging (for security,
288
+ * the actual session ID is not logged)
289
+ * @param request the Fastify request
290
+ * @returns hash of the session ID
291
+ */
292
+ getHashOfSessionId(request: FastifyRequest): string;
293
+ }