forked from keycloak/keycloak-nodejs-connect
-
Notifications
You must be signed in to change notification settings - Fork 0
/
keycloak.d.ts
446 lines (402 loc) · 17.6 KB
/
keycloak.d.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
import * as express from 'express'
/**
* The JavaScript module is exported as a single function, but for TypeScript we
* need to export the function and a set of interfaces so developers can assign
* types such as Grant, Token, etc. to variables in their own code.
*
* To achieve this we export "KeycloakConnect" that references a namespace
* containing our typings, and a static instance exposing the constructor
*/
declare const KeycloakConnect: KeycloakConnectStatic;
export = KeycloakConnect
interface KeycloakConnectStatic {
new (options?: KeycloakConnect.KeycloakOptions, config?: KeycloakConnect.KeycloakConfig|string): KeycloakConnect.Keycloak
}
declare namespace KeycloakConnect {
interface KeycloakConfig {
'confidential-port': string|number
'auth-server-url': string
'resource': string
'ssl-required': string
'bearer-only'?: boolean
realm: string
}
interface KeycloakOptions {
scope?: string
store?: any
cookies?: boolean
}
interface GrantProperties {
access_token?: Token
refresh_token?: Token
id_token?: Token
expires_in?: string
token_type?: string
}
interface Token {
isExpired(): boolean
hasRole(roleName: string): boolean
hasApplicationRole(appName: string, roleName: string): boolean
hasRealmRole(roleName: string): boolean
}
interface GrantManager {
/**
* Use the direct grant API to obtain a grant from Keycloak.
*
* The direct grant API must be enabled for the configured realm
* for this method to work. This function ostensibly provides a
* non-interactive, programatic way to login to a Keycloak realm.
*
* @param {String} username The username.
* @param {String} password The cleartext password.
*/
obtainDirectly(username: string, password: string): Promise<Grant>
/**
* Obtain a grant from a previous interactive login which results in a code.
*
* This is typically used by servers which receive the code through a
* redirect_uri when sending a user to Keycloak for an interactive login.
*
* An optional session ID and host may be provided if there is desire for
* Keycloak to be aware of this information. They may be used by Keycloak
* when session invalidation is triggered from the Keycloak console itself
* during its postbacks to `/k_logout` on the server.
*
* @param {String} code The code from a successful login redirected from Keycloak.
* @param {String} sessionId Optional opaque session-id.
* @param {String} sessionHost Optional session host for targetted Keycloak console post-backs.
*/
obtainFromCode(code: string, sessionid?: string, sessionHost?: string, callback?: (err: Error, grant: Grant) => void): Promise<Grant>
/**
* Obtain a service account grant.
* Client option 'Service Accounts Enabled' needs to be on.
*
* This method returns or promise or may optionally take a callback function.
*
* @param {Function} callback Optional callback, if not using promises.
*/
obtainFromClientCredentials (callback?: (err: Error, grant: Grant) => void, scopeParam?: string): Promise<Grant>
/**
* Ensure that a grant is *fresh*, refreshing if required & possible.
*
* If the access_token is not expired, the grant is left untouched.
*
* If the access_token is expired, and a refresh_token is available,
* the grant is refreshed, in place (no new object is created),
* and returned.
*
* If the access_token is expired and no refresh_token is available,
* an error is provided.
*
* @param {Grant} grant The grant object to ensure freshness of
*/
ensureFreshness (grant: Grant): Promise<Grant>
/**
* Perform live validation of an `access_token` against the Keycloak server.
*
* @param {Token|String} token The token to validate.
* @param {Function} callback Callback function if not using promises.
*
* @return {boolean} `false` if the token is invalid, or the same token if valid.
*/
validateAccessToken<T extends Token|string>(token: T): Promise<false|T>
/**
* Returns a user info JSON Object
* @param {Token|String} token
*/
userInfo<T extends Token|string, C>(token: T): Promise<C>
/**
* Create a `Grant` object from a string of JSON data.
*
* This method creates the `Grant` object, including
* the `access_token`, `refresh_token` and `id_token`
* if available, and validates each for expiration and
* against the known public-key of the server.
*
* @param {String|GrantProperties} rawData The raw JSON string received from the Keycloak server or from a client.
* @return {Promise} A promise reoslving a grant.
*/
createGrant(data: string|GrantProperties): Promise<Grant>
/**
* Validate the grant and all tokens contained therein.
*
* This method examines a grant (in place) and rejects
* if any of the tokens are invalid. After this method
* resolves, the passed grant is guaranteed to have
* valid tokens.
*
* @param {Grant} grant The grant to validate.
*
* @return {Promise} That resolves to a validated grant or
* rejects with an error if any of the tokens are invalid.
*/
validateGrant(grant: Grant): Promise<Grant>
/**
* Validate a token.
*
* This method accepts a token, and returns a promise
*
* If the token is valid the promise will be resolved with the token
*
* If the token is undefined or fails validation an applicable error is returned
*
* @return {Promise} That resolve a token
*/
validateToken(token: Token, expectedType?: string): Promise<Token>
}
interface Grant extends GrantProperties {
/**
* Update this grant in-place given data in another grant.
*
* This is used to avoid making client perform extra-bookkeeping
* to maintain the up-to-date/refreshed grant-set.
*/
update(grant: Grant): void
/**
* Returns the raw String of the grant, if available.
*
* If the raw string is unavailable (due to programatic construction)
* then `undefined` is returned.
*/
toString(): string|undefined
/**
* Determine if this grant is expired/out-of-date.
*
* Determination is made based upon the expiration status of the `access_token`.
*
* An expired grant *may* be possible to refresh, if a valid
* `refresh_token` is available.
*
* @return {boolean} `true` if expired, otherwise `false`.
*/
isExpired(): boolean
}
type GuardFn = (accessToken: Token, req: express.Request, res: express.Response) => boolean
interface EnforcerOptions {
response_mode?: string,
resource_server_id?: string,
claims?: (...args: any[]) => any
}
interface AuthZRequest {
audience?: string,
response_mode?: string,
claim_token?: string,
claim_token_format?: string,
permissions: {id: string, scopes: string[]}[]
}
interface Keycloak {
grantManager: GrantManager
/**
* Obtain an array of middleware for use in your application.
*
* Generally this should be installed at the root of your application,
* as it provides general wiring for Keycloak interaction, without actually
* causing Keycloak to get involved with any particular URL until asked
* by using `protect(...)`.
*
* Example:
*
* var app = express();
* var keycloak = new Keycloak();
* app.use( keycloak.middleware() );
*
* Options:
*
* - `logout` URL for logging a user out. Defaults to `/logout`.
* - `admin` Root URL for Keycloak admin callbacks. Defaults to `/`.
*
* @param {Object} options Optional options for specifying details.
*/
middleware(options?: { admin?: string, logout?: string }): express.RequestHandler[]
/**
* Apply protection middleware to an application or specific URL.
*
* If no `spec` parameter is provided, the subsequent handlers will
* be invoked if the user is authenticated, regardless of what roles
* he or she may or may not have.
*
* If a user is not currently authenticated, the middleware will cause
* the authentication workflow to begin by redirecting the user to the
* Keycloak installation to login. Upon successful login, the user will
* be redirected back to the originally-requested URL, fully-authenticated.
*
* If a `spec` is provided, the same flow as above will occur to ensure that
* a user it authenticated. Once authenticated, the spec will then be evaluated
* to determine if the user may or may not access the following resource.
*
* The `spec` may be either a `String`, specifying a single required role,
* or a function to make more fine-grained determination about access-control
*
* If the `spec` is a `String`, then the string will be interpreted as a
* role-specification according to the following rules:
*
* - If the string starts with `realm:`, the suffix is treated as the name
* of a realm-level role that is required for the user to have access.
* - If the string contains a colon, the portion before the colon is treated
* as the name of an application within the realm, and the portion after the
* colon is treated as a role within that application. The user then must have
* the named role within the named application to proceed.
* - If the string contains no colon, the entire string is interpreted as
* as the name of a role within the current application (defined through
* the installed `keycloak.json` as provisioned within Keycloak) that the
* user must have in order to proceed.
*
* Example
*
* // Users must have the `special-people` role within this application
* app.get( '/special/:page', keycloak.protect( 'special-people' ), mySpecialHandler );
*
* If the `spec` is a function, it may take up to two parameters in order to
* assist it in making an authorization decision: the access token, and the
* current HTTP request. It should return `true` if access is allowed, otherwise
* `false`.
*
* The `token` object has a method `hasRole(...)` which follows the same rules
* as above for `String`-based specs.
*
* // Ensure that users have either `nicepants` realm-level role, or `mr-fancypants` app-level role.
* function pants(token, request) {
* return token.hasRole( 'realm:nicepants') || token.hasRole( 'mr-fancypants');
* }
*
* app.get( '/fancy/:page', keycloak.protect( pants ), myPantsHandler );
*
* With no spec, simple authentication is all that is required:
*
* app.get( '/complain', keycloak.protect(), complaintHandler );
*
* @param {String} spec The protection spec (optional)
*/
protect(spec?: GuardFn|string): express.RequestHandler
/**
* Enforce access based on the given permissions. This method operates in two modes, depending on the `response_mode`
* defined for this policy enforcer.
*
* If `response_mode` is set to `token`, permissions are obtained using an specific grant type. As a consequence, the
* token with the permissions granted by the server is updated and made available to the application via `request.kauth.grant.access_token`.
* Use this mode when your application is using sessions and you want to cache previous decisions from the server, as well automatically handle
* refresh tokens. This mode is especially useful for applications acting as client and resource server.
*
* If `response_mode` is set to `permissions`, the server only returns the list of granted permissions (no oauth2 response).
* Previous decisions are not cached and the policy enforcer will query the server every time to get a decision.
* This is the default `response_mode`.
*
* You can set `response_mode` as follows:
*
* keycloak.enforcer('item:read', {response_mode: 'token'})
*
* In all cases, if the request is already populated with a valid access token (for instance, bearer tokens sent by clients to the application),
* the policy enforcer will first try to resolve permissions from the current token before querying the server.
*
* By default, the policy enforcer will use the `client_id` defined to the application (for instance, via `keycloak.json`) to
* reference a client in Keycloak that supports Keycloak Authorization Services. In this case, the client can not be public given
* that it is actually a resource server.
*
* If your application is acting as a client and resource server, you can use the following configuration to specify the client
* in Keycloak with the authorization settings:
*
* keycloak.enforcer('item:read', {resource_server_id: 'nodejs-apiserver'})
*
* It is recommended to use separated clients in Keycloak to represent your frontend and backend.
*
* If the application you are protecting is enabled with Keycloak authorization services and you have defined client credentials
* in `keycloak.json`, you can push additional claims to the server and make them available to your policies in order to make decisions.
* For that, you can define a `claims` configuration option which expects a `function` that returns a JSON with the claims you want to push:
*
* app.get('/protected/resource', keycloak.enforcer(['resource:view', 'resource:write'], {
claims: function(request) {
return {
"http.uri": ["/protected/resource"],
"user.agent": // get user agent from request
}
}
}), function (req, res) {
// access granted
});
*
* @param {string[]} permissions A single string representing a permission or an arrat of strings representing the permissions. For instance, 'item:read' or ['item:read', 'item:write'].
*/
enforcer(permissions: string[]|string, config?: EnforcerOptions): express.RequestHandler
/**
* Apply check SSO middleware to an application or specific URL.
*
* Check SSO will only authenticate the client if the user is already logged-in,
* if the user is not logged-in the browser will be redirected back
* to the originally-requested URL and remain unauthenticated.
*
*/
checkSso(): express.RequestHandler
/**
* Callback made upon successful authentication of a user.
*
* By default, this a no-op, but may assigned to another
* function for application-specific login which may be useful
* for linking authentication information from Keycloak to
* application-maintained user information.
*
* The `request.kauth.grant` object contains the relevant tokens
* which may be inspected.
*
* For instance, to obtain the unique subject ID:
*
* request.kauth.grant.id_token.sub => bf2056df-3803-4e49-b3ba-ff2b07d86995
*
* @param {Object} request The HTTP request.
*/
authenticated(req: express.Request): void
/**
* Callback made upon successful de-authentication of a user.
*
* By default, this is a no-op, but may be used by the application
* in the case it needs to remove information from the user's session
* or otherwise perform additional logic once a user is logged out.
*
* @param {Object} request The HTTP request.
*/
deauthenticated(req: express.Request): void
/**
* Replaceable function to handle access-denied responses.
*
* In the event the Keycloak middleware decides a user may
* not access a resource, or has failed to authenticate at all,
* this function will be called.
*
* By default, a simple string of "Access denied" along with
* an HTTP status code for 403 is returned. Chances are an
* application would prefer to render a fancy template.
* @param {Object} request The HTTP request.
* @param {Object} response The HTTP response.
*/
accessDenied(req: express.Request, res: express.Response): void
getGrant(req: express.Request, res: express.Response): Promise<Grant>
storeGrant(grant: Grant, req: express.Request, res: express.Response): Grant
unstoreGrant(sessionId: string): void
getGrantFromCode(code: string, req: express.Request, res: express.Response): Promise<Grant>
checkPermissions(authzRequest: AuthZRequest, request: express.Request, callback?: (json: any) => any): Promise<Grant>
loginUrl(uuid: string, redirectUrl: string): string
logoutUrl(redirectUrl: string, idTokenHint?: string): string
accountUrl(): string
// Uses deprecated method
// getAccount
/**
* Replaceable function to handle redirect behaviour.
*
* By default, all unauthorized requests will be redirected to the
* Keycloak login page unless your client is bearer-only.
* However, a confidential or public client may host both browsable and API endpoints.
* To prevent redirects on unauthenticated API requests and instead return an HTTP 401,
* you can override the redirectToLogin function.
*
* For example, this override checks if the url contains /api/ and disables login redirects:
*
* Keycloak.prototype.redirectToLogin = function(req) {
* var apiReqMatcher = /\/api\//i;
* return !apiReqMatcher.test(req.originalUrl || req.url);
* };
*
* @param {Object} request The HTTP request.
*/
redirectToLogin(req: express.Request): boolean
getConfig(): KeycloakConfig
}
}