@c9up/visa 0.1.1 → 0.1.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.
- package/dist/VisaManager.d.ts +40 -7
- package/dist/VisaManager.d.ts.map +1 -1
- package/dist/VisaManager.js +79 -3
- package/dist/VisaManager.js.map +1 -1
- package/dist/VisaProvider.d.ts.map +1 -1
- package/dist/VisaProvider.js +56 -0
- package/dist/VisaProvider.js.map +1 -1
- package/dist/authorize.d.ts +18 -0
- package/dist/authorize.d.ts.map +1 -1
- package/dist/authorize.js +6 -0
- package/dist/authorize.js.map +1 -1
- package/dist/config.d.ts +35 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js.map +1 -1
- package/dist/errors.d.ts +9 -3
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js.map +1 -1
- package/dist/guard.d.ts +21 -0
- package/dist/guard.d.ts.map +1 -1
- package/dist/guard.js +19 -0
- package/dist/guard.js.map +1 -1
- package/dist/index.d.ts +5 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/introspect.d.ts +9 -1
- package/dist/introspect.d.ts.map +1 -1
- package/dist/introspect.js +18 -1
- package/dist/introspect.js.map +1 -1
- package/dist/protectedResource.d.ts +81 -0
- package/dist/protectedResource.d.ts.map +1 -0
- package/dist/protectedResource.js +124 -0
- package/dist/protectedResource.js.map +1 -0
- package/dist/register.d.ts +96 -0
- package/dist/register.d.ts.map +1 -0
- package/dist/register.js +173 -0
- package/dist/register.js.map +1 -0
- package/dist/resource.d.ts +50 -0
- package/dist/resource.d.ts.map +1 -0
- package/dist/resource.js +101 -0
- package/dist/resource.js.map +1 -0
- package/dist/store.d.ts +25 -0
- package/dist/store.d.ts.map +1 -1
- package/dist/stores/atlas.d.ts +7 -0
- package/dist/stores/atlas.d.ts.map +1 -1
- package/dist/stores/atlas.js +70 -16
- package/dist/stores/atlas.js.map +1 -1
- package/dist/stores/memory.d.ts +4 -0
- package/dist/stores/memory.d.ts.map +1 -1
- package/dist/stores/memory.js +25 -0
- package/dist/stores/memory.js.map +1 -1
- package/dist/token.d.ts +2 -0
- package/dist/token.d.ts.map +1 -1
- package/dist/token.js +21 -1
- package/dist/token.js.map +1 -1
- package/dist/types.d.ts +42 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/VisaManager.ts +109 -3
- package/src/VisaProvider.ts +64 -0
- package/src/authorize.ts +27 -0
- package/src/config.ts +35 -0
- package/src/errors.ts +16 -2
- package/src/guard.ts +30 -0
- package/src/index.ts +25 -0
- package/src/introspect.ts +17 -0
- package/src/protectedResource.ts +171 -0
- package/src/register.ts +296 -0
- package/src/resource.ts +123 -0
- package/src/store.ts +29 -0
- package/src/stores/atlas.ts +99 -15
- package/src/stores/memory.ts +33 -0
- package/src/token.ts +45 -1
- package/src/types.ts +43 -0
- package/stubs/database/migrations/9000_create_visa_tables.stub +9 -0
package/dist/guard.js
CHANGED
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
*/
|
|
21
21
|
import { hashSecret, randomToken } from "./crypto.js";
|
|
22
22
|
import { verifyAccessToken } from "./introspect.js";
|
|
23
|
+
import { wwwAuthenticate } from "./protectedResource.js";
|
|
23
24
|
/**
|
|
24
25
|
* The token behind the current request.
|
|
25
26
|
*
|
|
@@ -202,6 +203,24 @@ export class VisaGuard {
|
|
|
202
203
|
const token = await this.createToken(user, abilities, options);
|
|
203
204
|
return { headers: { authorization: `Bearer ${token.value}` } };
|
|
204
205
|
}
|
|
206
|
+
/**
|
|
207
|
+
* The `WWW-Authenticate` value a 401 from this guard should carry.
|
|
208
|
+
*
|
|
209
|
+
* Returned rather than set: a warden strategy answers whether a credential
|
|
210
|
+
* is good, and the response belongs to whoever refuses the request. An
|
|
211
|
+
* exception handler sets it — `response.header('www-authenticate',
|
|
212
|
+
* guard.challenge())` — and with it a client that has no token learns
|
|
213
|
+
* where to get one instead of hitting a dead end.
|
|
214
|
+
*/
|
|
215
|
+
challenge(options = {}) {
|
|
216
|
+
return wwwAuthenticate({
|
|
217
|
+
...(this.#config.resource === undefined
|
|
218
|
+
? {}
|
|
219
|
+
: { resource: this.#config.resource }),
|
|
220
|
+
...(options.error === undefined ? {} : { error: options.error }),
|
|
221
|
+
...(options.scope === undefined ? {} : { scope: options.scope }),
|
|
222
|
+
});
|
|
223
|
+
}
|
|
205
224
|
async verify(presented) {
|
|
206
225
|
const store = this.#store();
|
|
207
226
|
const now = new Date();
|
package/dist/guard.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"guard.js","sourceRoot":"","sources":["../src/guard.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AACtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AA+
|
|
1
|
+
{"version":3,"file":"guard.js","sourceRoot":"","sources":["../src/guard.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -14,14 +14,17 @@ export { type AuthorizationRequest, type AuthorizeOptions, errorRedirect, issueA
|
|
|
14
14
|
export { assertGrantAllowed, authenticateClient, type ClientCredentials, readCredentials, redirectUriMatches, resolveScopes, } from "./clients.js";
|
|
15
15
|
export { defineConfig, type VisaConfigInput } from "./config.js";
|
|
16
16
|
export { hashSecret, randomToken, secretMatches, sha256 } from "./crypto.js";
|
|
17
|
-
export { type AuthorizationErrorCode, OAuthError, type ProtocolErrorCode, type TokenErrorCode, VisaError, } from "./errors.js";
|
|
17
|
+
export { type AuthorizationErrorCode, OAuthError, type ProtocolErrorCode, type RegistrationErrorCode, type TokenErrorCode, VisaError, } from "./errors.js";
|
|
18
18
|
export { type GuardClientResponse, type GuardResult, type GuardStore, type GuardUser, VisaAccessToken, VisaGuard, type VisaGuardConfig, visaGuard, } from "./guard.js";
|
|
19
19
|
export { introspect, revoke, verifyAccessToken } from "./introspect.js";
|
|
20
|
+
export { assertResourceIdentifier, type ChallengeOptions, PROTECTED_RESOURCE_PATH, type ProtectedResourceMetadata, type ProtectedResourceOptions, protectedResourceMetadata, protectedResourceMetadataUrl, wwwAuthenticate, } from "./protectedResource.js";
|
|
21
|
+
export { type ClientRegistrationRequest, type ClientRegistrationResponse, type RegistrationOptions, registrationResponse, validateRegistration, } from "./register.js";
|
|
22
|
+
export { audienceAllows, narrowResources, readResourceParameter, validateResources, } from "./resource.js";
|
|
20
23
|
export { clearVisa, default as visa, getVisa, setVisa, } from "./services/main.js";
|
|
21
24
|
export type { VisaStore } from "./store.js";
|
|
22
25
|
export { type AtlasDb, type AtlasQuery, AtlasStore, type AtlasStoreTables, } from "./stores/atlas.js";
|
|
23
26
|
export { MemoryStore } from "./stores/memory.js";
|
|
24
27
|
export { type TokenOptions, type TokenRequest, token } from "./token.js";
|
|
25
|
-
export type { AccessToken, AuthorizationCode, Client, ClientAuthMethod, Consent, GrantType, IntrospectionResponse, RefreshToken, TokenResponse, } from "./types.js";
|
|
28
|
+
export type { AccessToken, AuthorizationCode, AuthorizedApplication, Client, ClientAuthMethod, Consent, GrantType, IntrospectionResponse, RefreshToken, TokenResponse, } from "./types.js";
|
|
26
29
|
export { type AuthorizationOutcome, type VisaConfig, VisaManager, } from "./VisaManager.js";
|
|
27
30
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,oBAAoB,CAAC;AAE5B,OAAO,EACN,KAAK,oBAAoB,EACzB,KAAK,gBAAgB,EACrB,aAAa,EACb,sBAAsB,EACtB,eAAe,EACf,mBAAmB,EACnB,KAAK,gBAAgB,EACrB,4BAA4B,GAC5B,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACN,kBAAkB,EAClB,kBAAkB,EAClB,KAAK,iBAAiB,EACtB,eAAe,EACf,kBAAkB,EAClB,aAAa,GACb,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,YAAY,EAAE,KAAK,eAAe,EAAE,MAAM,aAAa,CAAC;AACjE,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC7E,OAAO,EACN,KAAK,sBAAsB,EAC3B,UAAU,EACV,KAAK,iBAAiB,EACtB,KAAK,cAAc,EACnB,SAAS,GACT,MAAM,aAAa,CAAC;AACrB,OAAO,EACN,KAAK,mBAAmB,EACxB,KAAK,WAAW,EAChB,KAAK,UAAU,EACf,KAAK,SAAS,EACd,eAAe,EACf,SAAS,EACT,KAAK,eAAe,EACpB,SAAS,GACT,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACxE,OAAO,EACN,SAAS,EACT,OAAO,IAAI,IAAI,EACf,OAAO,EACP,OAAO,GACP,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,EACN,KAAK,OAAO,EACZ,KAAK,UAAU,EACf,UAAU,EACV,KAAK,gBAAgB,GACrB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,KAAK,YAAY,EAAE,KAAK,YAAY,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACzE,YAAY,EACX,WAAW,EACX,iBAAiB,EACjB,MAAM,EACN,gBAAgB,EAChB,OAAO,EACP,SAAS,EACT,qBAAqB,EACrB,YAAY,EACZ,aAAa,GACb,MAAM,YAAY,CAAC;AACpB,OAAO,EACN,KAAK,oBAAoB,EACzB,KAAK,UAAU,EACf,WAAW,GACX,MAAM,kBAAkB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,oBAAoB,CAAC;AAE5B,OAAO,EACN,KAAK,oBAAoB,EACzB,KAAK,gBAAgB,EACrB,aAAa,EACb,sBAAsB,EACtB,eAAe,EACf,mBAAmB,EACnB,KAAK,gBAAgB,EACrB,4BAA4B,GAC5B,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACN,kBAAkB,EAClB,kBAAkB,EAClB,KAAK,iBAAiB,EACtB,eAAe,EACf,kBAAkB,EAClB,aAAa,GACb,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,YAAY,EAAE,KAAK,eAAe,EAAE,MAAM,aAAa,CAAC;AACjE,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC7E,OAAO,EACN,KAAK,sBAAsB,EAC3B,UAAU,EACV,KAAK,iBAAiB,EACtB,KAAK,qBAAqB,EAC1B,KAAK,cAAc,EACnB,SAAS,GACT,MAAM,aAAa,CAAC;AACrB,OAAO,EACN,KAAK,mBAAmB,EACxB,KAAK,WAAW,EAChB,KAAK,UAAU,EACf,KAAK,SAAS,EACd,eAAe,EACf,SAAS,EACT,KAAK,eAAe,EACpB,SAAS,GACT,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACxE,OAAO,EACN,wBAAwB,EACxB,KAAK,gBAAgB,EACrB,uBAAuB,EACvB,KAAK,yBAAyB,EAC9B,KAAK,wBAAwB,EAC7B,yBAAyB,EACzB,4BAA4B,EAC5B,eAAe,GACf,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACN,KAAK,yBAAyB,EAC9B,KAAK,0BAA0B,EAC/B,KAAK,mBAAmB,EACxB,oBAAoB,EACpB,oBAAoB,GACpB,MAAM,eAAe,CAAC;AACvB,OAAO,EACN,cAAc,EACd,eAAe,EACf,qBAAqB,EACrB,iBAAiB,GACjB,MAAM,eAAe,CAAC;AACvB,OAAO,EACN,SAAS,EACT,OAAO,IAAI,IAAI,EACf,OAAO,EACP,OAAO,GACP,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,EACN,KAAK,OAAO,EACZ,KAAK,UAAU,EACf,UAAU,EACV,KAAK,gBAAgB,GACrB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,KAAK,YAAY,EAAE,KAAK,YAAY,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACzE,YAAY,EACX,WAAW,EACX,iBAAiB,EACjB,qBAAqB,EACrB,MAAM,EACN,gBAAgB,EAChB,OAAO,EACP,SAAS,EACT,qBAAqB,EACrB,YAAY,EACZ,aAAa,GACb,MAAM,YAAY,CAAC;AACpB,OAAO,EACN,KAAK,oBAAoB,EACzB,KAAK,UAAU,EACf,WAAW,GACX,MAAM,kBAAkB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -17,6 +17,9 @@ export { hashSecret, randomToken, secretMatches, sha256 } from "./crypto.js";
|
|
|
17
17
|
export { OAuthError, VisaError, } from "./errors.js";
|
|
18
18
|
export { VisaAccessToken, VisaGuard, visaGuard, } from "./guard.js";
|
|
19
19
|
export { introspect, revoke, verifyAccessToken } from "./introspect.js";
|
|
20
|
+
export { assertResourceIdentifier, PROTECTED_RESOURCE_PATH, protectedResourceMetadata, protectedResourceMetadataUrl, wwwAuthenticate, } from "./protectedResource.js";
|
|
21
|
+
export { registrationResponse, validateRegistration, } from "./register.js";
|
|
22
|
+
export { audienceAllows, narrowResources, readResourceParameter, validateResources, } from "./resource.js";
|
|
20
23
|
export { clearVisa, default as visa, getVisa, setVisa, } from "./services/main.js";
|
|
21
24
|
export { AtlasStore, } from "./stores/atlas.js";
|
|
22
25
|
export { MemoryStore } from "./stores/memory.js";
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,oBAAoB,CAAC;AAE5B,OAAO,EAGN,aAAa,EACb,sBAAsB,EACtB,eAAe,EACf,mBAAmB,EAEnB,4BAA4B,GAC5B,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACN,kBAAkB,EAClB,kBAAkB,EAElB,eAAe,EACf,kBAAkB,EAClB,aAAa,GACb,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,YAAY,EAAwB,MAAM,aAAa,CAAC;AACjE,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC7E,OAAO,EAEN,UAAU,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,oBAAoB,CAAC;AAE5B,OAAO,EAGN,aAAa,EACb,sBAAsB,EACtB,eAAe,EACf,mBAAmB,EAEnB,4BAA4B,GAC5B,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACN,kBAAkB,EAClB,kBAAkB,EAElB,eAAe,EACf,kBAAkB,EAClB,aAAa,GACb,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,YAAY,EAAwB,MAAM,aAAa,CAAC;AACjE,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC7E,OAAO,EAEN,UAAU,EAIV,SAAS,GACT,MAAM,aAAa,CAAC;AACrB,OAAO,EAKN,eAAe,EACf,SAAS,EAET,SAAS,GACT,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACxE,OAAO,EACN,wBAAwB,EAExB,uBAAuB,EAGvB,yBAAyB,EACzB,4BAA4B,EAC5B,eAAe,GACf,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAIN,oBAAoB,EACpB,oBAAoB,GACpB,MAAM,eAAe,CAAC;AACvB,OAAO,EACN,cAAc,EACd,eAAe,EACf,qBAAqB,EACrB,iBAAiB,GACjB,MAAM,eAAe,CAAC;AACvB,OAAO,EACN,SAAS,EACT,OAAO,IAAI,IAAI,EACf,OAAO,EACP,OAAO,GACP,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EAGN,UAAU,GAEV,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAwC,KAAK,EAAE,MAAM,YAAY,CAAC;AAazE,OAAO,EAGN,WAAW,GACX,MAAM,kBAAkB,CAAC"}
|
package/dist/introspect.d.ts
CHANGED
|
@@ -24,11 +24,19 @@ export declare function revoke(request: Record<string, unknown>, credentials: Cl
|
|
|
24
24
|
* What a resource server calls on every request — so it reads the store
|
|
25
25
|
* directly instead of going through introspection's client authentication.
|
|
26
26
|
*/
|
|
27
|
-
export declare function verifyAccessToken(presented: string, store: Pick<VisaStore, "findAccessToken">, now?: Date
|
|
27
|
+
export declare function verifyAccessToken(presented: string, store: Pick<VisaStore, "findAccessToken">, now?: Date,
|
|
28
|
+
/**
|
|
29
|
+
* This resource's identifier (RFC 8707).
|
|
30
|
+
*
|
|
31
|
+
* Given, a token minted for a different resource is refused here rather
|
|
32
|
+
* than honoured — which is the entire point of binding one.
|
|
33
|
+
*/
|
|
34
|
+
resource?: string): Promise<{
|
|
28
35
|
clientId: string;
|
|
29
36
|
userId?: string;
|
|
30
37
|
scopes: string[];
|
|
31
38
|
expiresAt: Date;
|
|
32
39
|
lastUsedAt?: Date;
|
|
40
|
+
audience?: string[];
|
|
33
41
|
} | null>;
|
|
34
42
|
//# sourceMappingURL=introspect.d.ts.map
|
package/dist/introspect.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"introspect.d.ts","sourceRoot":"","sources":["../src/introspect.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAsB,KAAK,iBAAiB,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"introspect.d.ts","sourceRoot":"","sources":["../src/introspect.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAsB,KAAK,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAI1E,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAKxD,wBAAsB,UAAU,CAC/B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAChC,WAAW,EAAE,iBAAiB,EAC9B,KAAK,EAAE,SAAS,EAChB,GAAG,GAAE,IAAiB,EACtB,MAAM,CAAC,EAAE,MAAM,GACb,OAAO,CAAC,qBAAqB,CAAC,CAyDhC;AAED;;;;;;GAMG;AACH,wBAAsB,MAAM,CAC3B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAChC,WAAW,EAAE,iBAAiB,EAC9B,KAAK,EAAE,SAAS,EAChB,GAAG,GAAE,IAAiB,GACpB,OAAO,CAAC,IAAI,CAAC,CAqBf;AAED;;;;;GAKG;AACH,wBAAsB,iBAAiB,CACtC,SAAS,EAAE,MAAM,EAGjB,KAAK,EAAE,IAAI,CAAC,SAAS,EAAE,iBAAiB,CAAC,EACzC,GAAG,GAAE,IAAiB;AACtB;;;;;GAKG;AACH,QAAQ,CAAC,EAAE,MAAM,GACf,OAAO,CAAC;IACV,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,SAAS,EAAE,IAAI,CAAC;IAChB,UAAU,CAAC,EAAE,IAAI,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;CACpB,GAAG,IAAI,CAAC,CAoBR"}
|
package/dist/introspect.js
CHANGED
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
import { authenticateClient } from "./clients.js";
|
|
10
10
|
import { hashSecret } from "./crypto.js";
|
|
11
11
|
import { OAuthError } from "./errors.js";
|
|
12
|
+
import { audienceAllows } from "./resource.js";
|
|
12
13
|
/** `{ active: false }` — the only thing an inactive token ever reveals. */
|
|
13
14
|
const INACTIVE = { active: false };
|
|
14
15
|
export async function introspect(request, credentials, store, now = new Date(), issuer) {
|
|
@@ -39,6 +40,9 @@ export async function introspect(request, credentials, store, now = new Date(),
|
|
|
39
40
|
token_type: "Bearer",
|
|
40
41
|
exp: Math.floor(access.expiresAt.getTime() / 1000),
|
|
41
42
|
...(access.userId === undefined ? {} : { sub: access.userId }),
|
|
43
|
+
// RFC 8707 §3 names introspection as where a resource server learns
|
|
44
|
+
// what a token was minted for.
|
|
45
|
+
...(access.audience === undefined ? {} : { aud: access.audience }),
|
|
42
46
|
};
|
|
43
47
|
}
|
|
44
48
|
const refresh = await store.findRefreshToken(hash);
|
|
@@ -95,12 +99,24 @@ export async function revoke(request, credentials, store, now = new Date()) {
|
|
|
95
99
|
export async function verifyAccessToken(presented,
|
|
96
100
|
// Only the one read: a resource server that keeps nothing but tokens should
|
|
97
101
|
// not have to implement eleven methods it never calls.
|
|
98
|
-
store, now = new Date()
|
|
102
|
+
store, now = new Date(),
|
|
103
|
+
/**
|
|
104
|
+
* This resource's identifier (RFC 8707).
|
|
105
|
+
*
|
|
106
|
+
* Given, a token minted for a different resource is refused here rather
|
|
107
|
+
* than honoured — which is the entire point of binding one.
|
|
108
|
+
*/
|
|
109
|
+
resource) {
|
|
99
110
|
const token = await store.findAccessToken(hashSecret(presented));
|
|
100
111
|
if (token === null)
|
|
101
112
|
return null;
|
|
102
113
|
if (token.revokedAt !== undefined || token.expiresAt <= now)
|
|
103
114
|
return null;
|
|
115
|
+
// RFC 8707: a token bound to a resource is refused anywhere else. Unbound
|
|
116
|
+
// tokens are accepted — that is every token issued before a client started
|
|
117
|
+
// asking, and refusing them would break each one.
|
|
118
|
+
if (!audienceAllows(token.audience, resource))
|
|
119
|
+
return null;
|
|
104
120
|
return {
|
|
105
121
|
clientId: token.clientId,
|
|
106
122
|
...(token.userId === undefined ? {} : { userId: token.userId }),
|
|
@@ -111,6 +127,7 @@ store, now = new Date()) {
|
|
|
111
127
|
// The PREVIOUS use, before this one is recorded — which is what the
|
|
112
128
|
// upstream guard shows on `currentAccessToken.lastUsedAt`.
|
|
113
129
|
...(token.lastUsedAt === undefined ? {} : { lastUsedAt: token.lastUsedAt }),
|
|
130
|
+
...(token.audience === undefined ? {} : { audience: token.audience }),
|
|
114
131
|
};
|
|
115
132
|
}
|
|
116
133
|
function asString(value) {
|
package/dist/introspect.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"introspect.js","sourceRoot":"","sources":["../src/introspect.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,kBAAkB,EAA0B,MAAM,cAAc,CAAC;AAC1E,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"introspect.js","sourceRoot":"","sources":["../src/introspect.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What a protected resource says when it refuses, so a client can find its way
|
|
3
|
+
* in on its own (RFC 9728).
|
|
4
|
+
*
|
|
5
|
+
* Without this, a 401 is a dead end: the caller knows it needs a token and has
|
|
6
|
+
* no way to learn where tokens come from. With it, the refusal names a
|
|
7
|
+
* metadata document, the document names the authorization server, and an MCP
|
|
8
|
+
* client walks from one to the other unattended. That is the whole point — it
|
|
9
|
+
* is the difference between an agent that can connect and one that needs
|
|
10
|
+
* somebody to paste a URL into a config file.
|
|
11
|
+
*
|
|
12
|
+
* Nothing here is visa-specific: a resource server is free to be a different
|
|
13
|
+
* process from the authorization server, which is why the metadata takes the
|
|
14
|
+
* issuer as a value rather than reading one.
|
|
15
|
+
*/
|
|
16
|
+
/** The metadata document, §3.2. Only `resource` is required. */
|
|
17
|
+
export interface ProtectedResourceMetadata {
|
|
18
|
+
resource: string;
|
|
19
|
+
authorization_servers?: string[];
|
|
20
|
+
scopes_supported?: string[];
|
|
21
|
+
bearer_methods_supported?: string[];
|
|
22
|
+
resource_name?: string;
|
|
23
|
+
resource_documentation?: string;
|
|
24
|
+
jwks_uri?: string;
|
|
25
|
+
}
|
|
26
|
+
export interface ProtectedResourceOptions {
|
|
27
|
+
/** This resource's identifier — an absolute URI, no fragment. */
|
|
28
|
+
resource: string;
|
|
29
|
+
/** The authorization servers that issue tokens for it. */
|
|
30
|
+
authorizationServers?: readonly string[];
|
|
31
|
+
/** What a client may ask for here. RECOMMENDED by §3.2. */
|
|
32
|
+
scopesSupported?: readonly string[];
|
|
33
|
+
/** Where the token may travel. Defaults to the header, which is all visa reads. */
|
|
34
|
+
bearerMethodsSupported?: readonly string[];
|
|
35
|
+
resourceName?: string;
|
|
36
|
+
resourceDocumentation?: string;
|
|
37
|
+
}
|
|
38
|
+
/** The path the document is served at, §3. */
|
|
39
|
+
export declare const PROTECTED_RESOURCE_PATH = "/.well-known/oauth-protected-resource";
|
|
40
|
+
/**
|
|
41
|
+
* The well-known URL for a resource identifier.
|
|
42
|
+
*
|
|
43
|
+
* §3 inserts the well-known segment BETWEEN the host and the path, so a
|
|
44
|
+
* resource at `https://api.example/mcp` publishes at
|
|
45
|
+
* `https://api.example/.well-known/oauth-protected-resource/mcp` — not at the
|
|
46
|
+
* resource's own path with the segment appended, which is the easy mistake and
|
|
47
|
+
* the one that leaves a client fetching 404s.
|
|
48
|
+
*/
|
|
49
|
+
export declare function protectedResourceMetadataUrl(resource: string): string;
|
|
50
|
+
/** Build the document a client fetches after a 401. */
|
|
51
|
+
export declare function protectedResourceMetadata(options: ProtectedResourceOptions): ProtectedResourceMetadata;
|
|
52
|
+
export interface ChallengeOptions {
|
|
53
|
+
/** Where the metadata lives. Derived from the resource when omitted. */
|
|
54
|
+
resourceMetadata?: string;
|
|
55
|
+
/** This resource's identifier, used to derive the metadata URL. */
|
|
56
|
+
resource?: string;
|
|
57
|
+
/** `invalid_token`, `insufficient_scope` — RFC 6750 §3.1. */
|
|
58
|
+
error?: string;
|
|
59
|
+
errorDescription?: string;
|
|
60
|
+
/** What the caller would have needed, with `insufficient_scope`. */
|
|
61
|
+
scope?: readonly string[];
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* The `WWW-Authenticate` value for a 401, §5.1.
|
|
65
|
+
*
|
|
66
|
+
* Quoted values are checked rather than escaped: the header is a
|
|
67
|
+
* comma-separated list of quoted strings, and a value carrying a quote or a
|
|
68
|
+
* control character cannot be represented in it at all. A caller that built
|
|
69
|
+
* one from user input should hear about it here, not ship a header a client
|
|
70
|
+
* parses into something else.
|
|
71
|
+
*/
|
|
72
|
+
export declare function wwwAuthenticate(options?: ChallengeOptions): string;
|
|
73
|
+
/**
|
|
74
|
+
* A resource identifier is an absolute URI with no fragment (RFC 8707 §2).
|
|
75
|
+
*
|
|
76
|
+
* Checked where the metadata is built, because a resource that publishes an
|
|
77
|
+
* identifier its own tokens will not match is broken in a way only visible at
|
|
78
|
+
* the moment a client is refused.
|
|
79
|
+
*/
|
|
80
|
+
export declare function assertResourceIdentifier(resource: string): void;
|
|
81
|
+
//# sourceMappingURL=protectedResource.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"protectedResource.d.ts","sourceRoot":"","sources":["../src/protectedResource.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,gEAAgE;AAChE,MAAM,WAAW,yBAAyB;IACzC,QAAQ,EAAE,MAAM,CAAC;IACjB,qBAAqB,CAAC,EAAE,MAAM,EAAE,CAAC;IACjC,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC5B,wBAAwB,CAAC,EAAE,MAAM,EAAE,CAAC;IACpC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,wBAAwB;IACxC,iEAAiE;IACjE,QAAQ,EAAE,MAAM,CAAC;IACjB,0DAA0D;IAC1D,oBAAoB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACzC,2DAA2D;IAC3D,eAAe,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC,mFAAmF;IACnF,sBAAsB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC3C,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,qBAAqB,CAAC,EAAE,MAAM,CAAC;CAC/B;AAED,8CAA8C;AAC9C,eAAO,MAAM,uBAAuB,0CAA0C,CAAC;AAE/E;;;;;;;;GAQG;AACH,wBAAgB,4BAA4B,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAOrE;AAED,uDAAuD;AACvD,wBAAgB,yBAAyB,CACxC,OAAO,EAAE,wBAAwB,GAC/B,yBAAyB,CAoB3B;AAED,MAAM,WAAW,gBAAgB;IAChC,wEAAwE;IACxE,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,mEAAmE;IACnE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,6DAA6D;IAC7D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,oEAAoE;IACpE,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC1B;AAED;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,OAAO,GAAE,gBAAqB,GAAG,MAAM,CAwBtE;AAsBD;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAU/D"}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What a protected resource says when it refuses, so a client can find its way
|
|
3
|
+
* in on its own (RFC 9728).
|
|
4
|
+
*
|
|
5
|
+
* Without this, a 401 is a dead end: the caller knows it needs a token and has
|
|
6
|
+
* no way to learn where tokens come from. With it, the refusal names a
|
|
7
|
+
* metadata document, the document names the authorization server, and an MCP
|
|
8
|
+
* client walks from one to the other unattended. That is the whole point — it
|
|
9
|
+
* is the difference between an agent that can connect and one that needs
|
|
10
|
+
* somebody to paste a URL into a config file.
|
|
11
|
+
*
|
|
12
|
+
* Nothing here is visa-specific: a resource server is free to be a different
|
|
13
|
+
* process from the authorization server, which is why the metadata takes the
|
|
14
|
+
* issuer as a value rather than reading one.
|
|
15
|
+
*/
|
|
16
|
+
/** The path the document is served at, §3. */
|
|
17
|
+
export const PROTECTED_RESOURCE_PATH = "/.well-known/oauth-protected-resource";
|
|
18
|
+
/**
|
|
19
|
+
* The well-known URL for a resource identifier.
|
|
20
|
+
*
|
|
21
|
+
* §3 inserts the well-known segment BETWEEN the host and the path, so a
|
|
22
|
+
* resource at `https://api.example/mcp` publishes at
|
|
23
|
+
* `https://api.example/.well-known/oauth-protected-resource/mcp` — not at the
|
|
24
|
+
* resource's own path with the segment appended, which is the easy mistake and
|
|
25
|
+
* the one that leaves a client fetching 404s.
|
|
26
|
+
*/
|
|
27
|
+
export function protectedResourceMetadataUrl(resource) {
|
|
28
|
+
const url = new URL(resource);
|
|
29
|
+
const path = url.pathname === "/" ? "" : url.pathname.replace(/\/$/, "");
|
|
30
|
+
url.pathname = `${PROTECTED_RESOURCE_PATH}${path}`;
|
|
31
|
+
url.search = "";
|
|
32
|
+
url.hash = "";
|
|
33
|
+
return url.href;
|
|
34
|
+
}
|
|
35
|
+
/** Build the document a client fetches after a 401. */
|
|
36
|
+
export function protectedResourceMetadata(options) {
|
|
37
|
+
assertResourceIdentifier(options.resource);
|
|
38
|
+
return {
|
|
39
|
+
resource: options.resource,
|
|
40
|
+
...(options.authorizationServers === undefined
|
|
41
|
+
? {}
|
|
42
|
+
: { authorization_servers: [...options.authorizationServers] }),
|
|
43
|
+
...(options.scopesSupported === undefined
|
|
44
|
+
? {}
|
|
45
|
+
: { scopes_supported: [...options.scopesSupported] }),
|
|
46
|
+
bearer_methods_supported: [
|
|
47
|
+
...(options.bearerMethodsSupported ?? ["header"]),
|
|
48
|
+
],
|
|
49
|
+
...(options.resourceName === undefined
|
|
50
|
+
? {}
|
|
51
|
+
: { resource_name: options.resourceName }),
|
|
52
|
+
...(options.resourceDocumentation === undefined
|
|
53
|
+
? {}
|
|
54
|
+
: { resource_documentation: options.resourceDocumentation }),
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* The `WWW-Authenticate` value for a 401, §5.1.
|
|
59
|
+
*
|
|
60
|
+
* Quoted values are checked rather than escaped: the header is a
|
|
61
|
+
* comma-separated list of quoted strings, and a value carrying a quote or a
|
|
62
|
+
* control character cannot be represented in it at all. A caller that built
|
|
63
|
+
* one from user input should hear about it here, not ship a header a client
|
|
64
|
+
* parses into something else.
|
|
65
|
+
*/
|
|
66
|
+
export function wwwAuthenticate(options = {}) {
|
|
67
|
+
const metadataUrl = options.resourceMetadata ??
|
|
68
|
+
(options.resource === undefined
|
|
69
|
+
? undefined
|
|
70
|
+
: protectedResourceMetadataUrl(options.resource));
|
|
71
|
+
const parameters = [];
|
|
72
|
+
if (options.error !== undefined)
|
|
73
|
+
parameters.push(["error", options.error]);
|
|
74
|
+
if (options.errorDescription !== undefined) {
|
|
75
|
+
parameters.push(["error_description", options.errorDescription]);
|
|
76
|
+
}
|
|
77
|
+
if (options.scope !== undefined && options.scope.length > 0) {
|
|
78
|
+
parameters.push(["scope", options.scope.join(" ")]);
|
|
79
|
+
}
|
|
80
|
+
if (metadataUrl !== undefined) {
|
|
81
|
+
parameters.push(["resource_metadata", metadataUrl]);
|
|
82
|
+
}
|
|
83
|
+
if (parameters.length === 0)
|
|
84
|
+
return "Bearer";
|
|
85
|
+
const rendered = parameters
|
|
86
|
+
.map(([key, value]) => `${key}="${quotable(value, key)}"`)
|
|
87
|
+
.join(", ");
|
|
88
|
+
return `Bearer ${rendered}`;
|
|
89
|
+
}
|
|
90
|
+
function quotable(value, parameter) {
|
|
91
|
+
// A quoted-string holds neither a bare quote nor a control character, and
|
|
92
|
+
// neither can be escaped into one usefully — a client would read the header
|
|
93
|
+
// as a different set of parameters.
|
|
94
|
+
for (const character of value) {
|
|
95
|
+
const code = character.codePointAt(0) ?? 0;
|
|
96
|
+
if (character === '"' ||
|
|
97
|
+
character === "\\" ||
|
|
98
|
+
code < 0x20 ||
|
|
99
|
+
code === 0x7f) {
|
|
100
|
+
throw new Error(`[visa] ${parameter} cannot go in a WWW-Authenticate header: it holds a quote, a backslash or a control character`);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
return value;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* A resource identifier is an absolute URI with no fragment (RFC 8707 §2).
|
|
107
|
+
*
|
|
108
|
+
* Checked where the metadata is built, because a resource that publishes an
|
|
109
|
+
* identifier its own tokens will not match is broken in a way only visible at
|
|
110
|
+
* the moment a client is refused.
|
|
111
|
+
*/
|
|
112
|
+
export function assertResourceIdentifier(resource) {
|
|
113
|
+
let url;
|
|
114
|
+
try {
|
|
115
|
+
url = new URL(resource);
|
|
116
|
+
}
|
|
117
|
+
catch {
|
|
118
|
+
throw new Error(`[visa] resource must be an absolute URI: ${resource}`);
|
|
119
|
+
}
|
|
120
|
+
if (url.hash !== "") {
|
|
121
|
+
throw new Error(`[visa] resource must not carry a fragment: ${resource}`);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
//# sourceMappingURL=protectedResource.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"protectedResource.js","sourceRoot":"","sources":["../src/protectedResource.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Clients that register themselves (RFC 7591).
|
|
3
|
+
*
|
|
4
|
+
* An MCP client such as claude.ai or ChatGPT has nobody to fill in a form for
|
|
5
|
+
* it: it discovers this server, registers, and comes back with an id. Without
|
|
6
|
+
* this the only way in is a human pasting credentials somewhere.
|
|
7
|
+
*
|
|
8
|
+
* OFF unless the application turns it on, and that is the important part. Open
|
|
9
|
+
* registration means anyone who can reach the endpoint can create a client —
|
|
10
|
+
* the RFC says a server SHOULD allow it for interoperability, and also says
|
|
11
|
+
* the endpoint MAY be protected (§1.2, §3). The safe default here is the one
|
|
12
|
+
* the RFC permits rather than the one it encourages, because an authorization
|
|
13
|
+
* server that silently accepts registrations is a thing nobody asked for. Turn
|
|
14
|
+
* it on deliberately, and with an initial access token if the deployment is
|
|
15
|
+
* not meant to be open.
|
|
16
|
+
*
|
|
17
|
+
* A registered client gets exactly what this server allows: the grants,
|
|
18
|
+
* scopes and auth methods in the configuration, never what the request asked
|
|
19
|
+
* for. That is the difference between letting a client name itself and letting
|
|
20
|
+
* it decide what it may do.
|
|
21
|
+
*/
|
|
22
|
+
import type { Client, ClientAuthMethod, GrantType } from "./types.js";
|
|
23
|
+
/** The metadata a request may send (§2). Unknown members are ignored. */
|
|
24
|
+
export interface ClientRegistrationRequest {
|
|
25
|
+
redirect_uris?: unknown;
|
|
26
|
+
token_endpoint_auth_method?: unknown;
|
|
27
|
+
grant_types?: unknown;
|
|
28
|
+
response_types?: unknown;
|
|
29
|
+
client_name?: unknown;
|
|
30
|
+
client_uri?: unknown;
|
|
31
|
+
logo_uri?: unknown;
|
|
32
|
+
scope?: unknown;
|
|
33
|
+
contacts?: unknown;
|
|
34
|
+
tos_uri?: unknown;
|
|
35
|
+
policy_uri?: unknown;
|
|
36
|
+
software_id?: unknown;
|
|
37
|
+
software_version?: unknown;
|
|
38
|
+
software_statement?: unknown;
|
|
39
|
+
/**
|
|
40
|
+
* Whatever else the client sent.
|
|
41
|
+
*
|
|
42
|
+
* §2 says a server ignores metadata it does not understand, and this is a
|
|
43
|
+
* parsed HTTP body — a client that sends `client_id` hoping to pick its own
|
|
44
|
+
* is a real thing, and it lands here rather than being a type error nobody
|
|
45
|
+
* sees at run time.
|
|
46
|
+
*/
|
|
47
|
+
[member: string]: unknown;
|
|
48
|
+
}
|
|
49
|
+
/** The 201 body (§3.2.1). */
|
|
50
|
+
export interface ClientRegistrationResponse {
|
|
51
|
+
client_id: string;
|
|
52
|
+
client_secret?: string;
|
|
53
|
+
/** Seconds since the epoch. */
|
|
54
|
+
client_id_issued_at: number;
|
|
55
|
+
/** REQUIRED when a secret was issued. `0` means it does not expire. */
|
|
56
|
+
client_secret_expires_at?: number;
|
|
57
|
+
redirect_uris: string[];
|
|
58
|
+
grant_types: GrantType[];
|
|
59
|
+
token_endpoint_auth_method: ClientAuthMethod;
|
|
60
|
+
client_name: string;
|
|
61
|
+
scope?: string;
|
|
62
|
+
}
|
|
63
|
+
export interface RegistrationOptions {
|
|
64
|
+
/** Nothing happens unless this is true. */
|
|
65
|
+
enabled?: boolean;
|
|
66
|
+
/**
|
|
67
|
+
* Require this bearer token on the registration request.
|
|
68
|
+
*
|
|
69
|
+
* Left out, the endpoint is open — which is what an MCP client that has
|
|
70
|
+
* never met you needs, and what a deployment on the public internet should
|
|
71
|
+
* think about before shipping.
|
|
72
|
+
*/
|
|
73
|
+
initialAccessToken?: string;
|
|
74
|
+
/** What a self-registered client may ever ask for. Defaults to none. */
|
|
75
|
+
scopes?: readonly string[];
|
|
76
|
+
/** Which grants it may use. Defaults to the authorization code flow and refresh. */
|
|
77
|
+
grantTypes?: readonly GrantType[];
|
|
78
|
+
/** Seconds until an issued secret expires. Omitted means it does not (§3.2.1). */
|
|
79
|
+
secretTtlSeconds?: number;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Check a registration request and say what the client may be.
|
|
83
|
+
*
|
|
84
|
+
* Returns the client to store and the plaintext secret, if one was issued —
|
|
85
|
+
* the caller persists the first and hands back the second, once.
|
|
86
|
+
*/
|
|
87
|
+
export declare function validateRegistration(request: ClientRegistrationRequest, options: RegistrationOptions, presentedToken?: string): {
|
|
88
|
+
redirectUris: string[];
|
|
89
|
+
grantTypes: GrantType[];
|
|
90
|
+
scopes: string[];
|
|
91
|
+
tokenEndpointAuthMethod: ClientAuthMethod;
|
|
92
|
+
name: string;
|
|
93
|
+
};
|
|
94
|
+
/** The 201 body for a client that was just created. */
|
|
95
|
+
export declare function registrationResponse(client: Client, issuedAt: Date, secret: string | undefined, options: RegistrationOptions): ClientRegistrationResponse;
|
|
96
|
+
//# sourceMappingURL=register.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"register.d.ts","sourceRoot":"","sources":["../src/register.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAGH,OAAO,KAAK,EAAE,MAAM,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAEtE,yEAAyE;AACzE,MAAM,WAAW,yBAAyB;IACzC,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,0BAA0B,CAAC,EAAE,OAAO,CAAC;IACrC,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B;;;;;;;OAOG;IACH,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC;CAC1B;AAED,6BAA6B;AAC7B,MAAM,WAAW,0BAA0B;IAC1C,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,+BAA+B;IAC/B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,uEAAuE;IACvE,wBAAwB,CAAC,EAAE,MAAM,CAAC;IAClC,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,WAAW,EAAE,SAAS,EAAE,CAAC;IACzB,0BAA0B,EAAE,gBAAgB,CAAC;IAC7C,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,mBAAmB;IACnC,2CAA2C;IAC3C,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;;;;OAMG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,wEAAwE;IACxE,MAAM,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC3B,oFAAoF;IACpF,UAAU,CAAC,EAAE,SAAS,SAAS,EAAE,CAAC;IAClC,kFAAkF;IAClF,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC1B;AAOD;;;;;GAKG;AACH,wBAAgB,oBAAoB,CACnC,OAAO,EAAE,yBAAyB,EAClC,OAAO,EAAE,mBAAmB,EAC5B,cAAc,CAAC,EAAE,MAAM,GACrB;IACF,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,UAAU,EAAE,SAAS,EAAE,CAAC;IACxB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,uBAAuB,EAAE,gBAAgB,CAAC;IAC1C,IAAI,EAAE,MAAM,CAAC;CACb,CAmDA;AAED,uDAAuD;AACvD,wBAAgB,oBAAoB,CACnC,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,IAAI,EACd,MAAM,EAAE,MAAM,GAAG,SAAS,EAC1B,OAAO,EAAE,mBAAmB,GAC1B,0BAA0B,CAsB5B"}
|