@boopkit/cap-oauth-server 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/capability.json +120 -0
- package/dist/authorization-code-service.d.ts +105 -0
- package/dist/authorization-code-service.d.ts.map +1 -0
- package/dist/authorization-code-service.js +142 -0
- package/dist/authorization-code-service.js.map +1 -0
- package/dist/bearer.d.ts +146 -0
- package/dist/bearer.d.ts.map +1 -0
- package/dist/bearer.js +150 -0
- package/dist/bearer.js.map +1 -0
- package/dist/body-field.d.ts +24 -0
- package/dist/body-field.d.ts.map +1 -0
- package/dist/body-field.js +43 -0
- package/dist/body-field.js.map +1 -0
- package/dist/client-registry-service.d.ts +120 -0
- package/dist/client-registry-service.d.ts.map +1 -0
- package/dist/client-registry-service.js +450 -0
- package/dist/client-registry-service.js.map +1 -0
- package/dist/config.d.ts +82 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +157 -0
- package/dist/config.js.map +1 -0
- package/dist/connections-controller.d.ts +106 -0
- package/dist/connections-controller.d.ts.map +1 -0
- package/dist/connections-controller.js +161 -0
- package/dist/connections-controller.js.map +1 -0
- package/dist/consent-controller.d.ts +197 -0
- package/dist/consent-controller.d.ts.map +1 -0
- package/dist/consent-controller.js +532 -0
- package/dist/consent-controller.js.map +1 -0
- package/dist/discovery-controller.d.ts +16 -0
- package/dist/discovery-controller.d.ts.map +1 -0
- package/dist/discovery-controller.js +52 -0
- package/dist/discovery-controller.js.map +1 -0
- package/dist/discovery.d.ts +95 -0
- package/dist/discovery.d.ts.map +1 -0
- package/dist/discovery.js +101 -0
- package/dist/discovery.js.map +1 -0
- package/dist/errors.d.ts +26 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +41 -0
- package/dist/errors.js.map +1 -0
- package/dist/express.d.ts +66 -0
- package/dist/express.d.ts.map +1 -0
- package/dist/express.js +3 -0
- package/dist/express.js.map +1 -0
- package/dist/grant-service.d.ts +102 -0
- package/dist/grant-service.d.ts.map +1 -0
- package/dist/grant-service.js +137 -0
- package/dist/grant-service.js.map +1 -0
- package/dist/index.d.ts +67 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +148 -0
- package/dist/index.js.map +1 -0
- package/dist/metadata-document.d.ts +60 -0
- package/dist/metadata-document.d.ts.map +1 -0
- package/dist/metadata-document.js +148 -0
- package/dist/metadata-document.js.map +1 -0
- package/dist/oauth-error.d.ts +45 -0
- package/dist/oauth-error.d.ts.map +1 -0
- package/dist/oauth-error.js +51 -0
- package/dist/oauth-error.js.map +1 -0
- package/dist/pkce.d.ts +29 -0
- package/dist/pkce.d.ts.map +1 -0
- package/dist/pkce.js +65 -0
- package/dist/pkce.js.map +1 -0
- package/dist/property-array.d.ts +60 -0
- package/dist/property-array.d.ts.map +1 -0
- package/dist/property-array.js +31 -0
- package/dist/property-array.js.map +1 -0
- package/dist/public-id.d.ts +35 -0
- package/dist/public-id.d.ts.map +1 -0
- package/dist/public-id.js +76 -0
- package/dist/public-id.js.map +1 -0
- package/dist/rate-limit.d.ts +56 -0
- package/dist/rate-limit.d.ts.map +1 -0
- package/dist/rate-limit.js +55 -0
- package/dist/rate-limit.js.map +1 -0
- package/dist/redirect-uri.d.ts +89 -0
- package/dist/redirect-uri.d.ts.map +1 -0
- package/dist/redirect-uri.js +249 -0
- package/dist/redirect-uri.js.map +1 -0
- package/dist/registration-controller.d.ts +62 -0
- package/dist/registration-controller.d.ts.map +1 -0
- package/dist/registration-controller.js +79 -0
- package/dist/registration-controller.js.map +1 -0
- package/dist/request-client.d.ts +19 -0
- package/dist/request-client.d.ts.map +1 -0
- package/dist/request-client.js +32 -0
- package/dist/request-client.js.map +1 -0
- package/dist/revocation-controller.d.ts +28 -0
- package/dist/revocation-controller.d.ts.map +1 -0
- package/dist/revocation-controller.js +176 -0
- package/dist/revocation-controller.js.map +1 -0
- package/dist/revocation-service.d.ts +113 -0
- package/dist/revocation-service.d.ts.map +1 -0
- package/dist/revocation-service.js +121 -0
- package/dist/revocation-service.js.map +1 -0
- package/dist/token-controller.d.ts +79 -0
- package/dist/token-controller.d.ts.map +1 -0
- package/dist/token-controller.js +207 -0
- package/dist/token-controller.js.map +1 -0
- package/dist/token-service.d.ts +175 -0
- package/dist/token-service.d.ts.map +1 -0
- package/dist/token-service.js +251 -0
- package/dist/token-service.js.map +1 -0
- package/dist/types.d.ts +130 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +13 -0
- package/dist/types.js.map +1 -0
- package/dist/user-store.d.ts +110 -0
- package/dist/user-store.d.ts.map +1 -0
- package/dist/user-store.js +40 -0
- package/dist/user-store.js.map +1 -0
- package/package.json +37 -0
- package/scaffold/prisma/schema/oauth-clients.prisma +80 -0
- package/scaffold/reference/oauth-server.ref.md +478 -0
- package/scaffold/src/middleware/oauth-server.ts +227 -0
- package/scaffold/src/scripts/seed-oauth-clients.ts +72 -0
- package/scaffold/src/services/oauth-server.service.ts +101 -0
- package/scaffold/styles/oauth-server.css +345 -0
- package/scaffold/views/oauth-connected-clients.hbs +98 -0
- package/scaffold/views/oauth-consent-error.hbs +22 -0
- package/scaffold/views/oauth-consent.hbs +138 -0
- package/scaffold/views/oauth-disconnect-confirm.hbs +57 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @boopkit/cap-oauth-server — an OAuth 2.1 authorization server and resource
|
|
3
|
+
* server for a boop application.
|
|
4
|
+
*
|
|
5
|
+
* Slice 1 shipped the parts every later slice speaks in terms of: the client
|
|
6
|
+
* registry that knows who is asking, and the discovery documents that tell a
|
|
7
|
+
* client what we are. Slice 2 adds the grant itself — the consent screen, the
|
|
8
|
+
* authorization code, `POST /oauth/token`, and enough of a resource-server
|
|
9
|
+
* guard to make an authenticated call real. Slice 3 makes that guard something
|
|
10
|
+
* a route can defend itself with — `requireOAuth(...scopes)` and its RFC 6750
|
|
11
|
+
* refusals — adds soft revocation, and gives a person the two screens where
|
|
12
|
+
* they see and disconnect what they have connected.
|
|
13
|
+
*
|
|
14
|
+
* **The identity boundary.** Nothing in this package reaches a user, an
|
|
15
|
+
* account, or an identity except through `@boopkit/cap-users`' public surface.
|
|
16
|
+
* The one table it owns is `oauth_clients`, which describes software rather
|
|
17
|
+
* than people. `tests/packages/cap-oauth-server-import-audit.test.ts` enforces
|
|
18
|
+
* that mechanically.
|
|
19
|
+
*/
|
|
20
|
+
import './express.js';
|
|
21
|
+
export { classifyRedirectUri, matchRedirectUri, matchesAnyRedirectUri, isLoopbackHost, } from './redirect-uri.js';
|
|
22
|
+
export type { RedirectUriClassification, RedirectUriShape } from './redirect-uri.js';
|
|
23
|
+
export { generateClientPublicId, isValidClientPublicId, CLIENT_PUBLIC_ID_ALPHABET, CLIENT_PUBLIC_ID_LENGTH, } from './public-id.js';
|
|
24
|
+
export { ClientRegistryError, isClientRegistryError } from './errors.js';
|
|
25
|
+
export type { ClientRegistryErrorCode } from './errors.js';
|
|
26
|
+
export { createClientRegistryService, validateRedirectUris, DEFAULT_GRANT_TYPES, DEFAULT_RESPONSE_TYPES, DEFAULT_METADATA_MAX_AGE_MS, DEFAULT_ABANDONED_CLIENT_TTL_MS, DEFAULT_MAX_REGISTERED_CLIENTS, } from './client-registry-service.js';
|
|
27
|
+
export type { ClientRegistryService, ClientRegistryServiceOptions, PruneOptions, } from './client-registry-service.js';
|
|
28
|
+
export { fetchMetadataDocument, isValidMetadataUri, DEFAULT_METADATA_TIMEOUT_MS, DEFAULT_METADATA_MAX_BYTES, DEFAULT_METADATA_MAX_REDIRECTS, } from './metadata-document.js';
|
|
29
|
+
export type { FetchLike, FetchLikeResponse, MetadataFetchOptions, } from './metadata-document.js';
|
|
30
|
+
export { buildAuthorizationServerMetadata, buildProtectedResourceMetadata, CODE_CHALLENGE_METHODS_SUPPORTED, DEVICE_CODE_GRANT_TYPE, DEFAULT_SCOPES_SUPPORTED, DISCOVERY_MAX_AGE_SECONDS, } from './discovery.js';
|
|
31
|
+
export type { DiscoveryConfig, AuthorizationServerMetadata, ProtectedResourceMetadata, } from './discovery.js';
|
|
32
|
+
export { readServerConfig, clampTtlSeconds, OauthServerConfigError, DEFAULT_ACCESS_TOKEN_TTL_SECONDS, DEFAULT_REFRESH_TOKEN_TTL_SECONDS, ACCESS_TOKEN_TTL_BOUNDS, REFRESH_TOKEN_TTL_BOUNDS, } from './config.js';
|
|
33
|
+
export type { ServerConfig, ReadConfigOptions } from './config.js';
|
|
34
|
+
export { createDiscoveryHandlers, createDiscoveryRouter } from './discovery-controller.js';
|
|
35
|
+
export type { DiscoveryHandlers } from './discovery-controller.js';
|
|
36
|
+
export { createRegistrationHandlers, createRegistrationRouter, toRegistrationResponse, } from './registration-controller.js';
|
|
37
|
+
export type { RegistrationHandlerDeps, RegistrationRouterOptions, } from './registration-controller.js';
|
|
38
|
+
export { createRegistrationRateLimiter, DEFAULT_REGISTRATION_RATE_LIMIT, DEFAULT_REGISTRATION_RATE_WINDOW_MS, } from './rate-limit.js';
|
|
39
|
+
export type { RateLimiterOptions, RegistrationRateLimiter } from './rate-limit.js';
|
|
40
|
+
export { CLIENT_MODES } from './types.js';
|
|
41
|
+
export type { ClientMode, ClientStatus, OauthClient, OauthClientDelegate, ClientMetadataInput, ClientIdMetadataDocument, StaticClientInput, } from './types.js';
|
|
42
|
+
export { createTokenService, buildIdentityKey, AUTHORIZATION_CODE_TTL_SECONDS, OAUTH_CODE_DOMAIN, OAUTH_ACCESS_DOMAIN, OAUTH_REFRESH_DOMAIN, } from './token-service.js';
|
|
43
|
+
export type { TokenService, TokenServiceOptions, OAuthTokenDomain, MintedToken, ResolvedToken, } from './token-service.js';
|
|
44
|
+
export { createGrantService, isGrantActive, OAUTH_GRANTS_PROPERTY, OAUTH_GRANTS_INFO_SCHEMA, } from './grant-service.js';
|
|
45
|
+
export type { GrantService, GrantServiceOptions, GrantsSnapshot, OAuthGrantRecord, ApproveGrantInput, } from './grant-service.js';
|
|
46
|
+
export { createAuthorizationCodeService, OAUTH_CODES_PROPERTY, OAUTH_CODES_INFO_SCHEMA, } from './authorization-code-service.js';
|
|
47
|
+
export type { AuthorizationCodeService, AuthorizationCodeServiceOptions, AuthorizationCodeRecord, IssueCodeInput, RedeemCodeInput, RedeemFailure, RedeemResult, } from './authorization-code-service.js';
|
|
48
|
+
export { CODE_CHALLENGE_METHOD, deriveCodeChallenge, isValidCodeChallenge, isValidCodeVerifier, verifyCodeChallenge, } from './pkce.js';
|
|
49
|
+
export { OAuthError, isOAuthError } from './oauth-error.js';
|
|
50
|
+
export type { OAuthErrorCode } from './oauth-error.js';
|
|
51
|
+
export { isStaleWriteError } from './user-store.js';
|
|
52
|
+
export type { IdentityStore, PropertyStore, PropertyWriteOptions, StoredIdentity, StoredProperty, } from './user-store.js';
|
|
53
|
+
export { readArray, writeArray } from './property-array.js';
|
|
54
|
+
export type { ArraySnapshot } from './property-array.js';
|
|
55
|
+
export { createConsentHandlers, createConsentRouter, monogramFor, provenanceFor, safeLogoUri, scopeDescriptionsFrom, toScopeViews, warnUndescribedScopes, SCOPE_DESCRIPTIONS_LOCAL, } from './consent-controller.js';
|
|
56
|
+
export type { AuthorizationRequest, ConsentCredentials, ConsentHandlers, ConsentHandlerDeps, ConsentRegister, ConsentRegistration, ConsentRouterOptions, ConsentScopeView, ConsentSession, ConsentSignIn, ConsentVariant, ScopeDescriptions, } from './consent-controller.js';
|
|
57
|
+
export { createTokenHandlers, createTokenRouter, parseScopes, OFFLINE_ACCESS_SCOPE, } from './token-controller.js';
|
|
58
|
+
export type { TokenHandlerDeps, TokenRouterOptions, TokenResponse, } from './token-controller.js';
|
|
59
|
+
export { createOAuthBearerMiddleware, createOAuthResourceServer, createOAuthTokenResolver, missingScopes, requireOAuth, DEFAULT_BEARER_CHALLENGE, } from './bearer.js';
|
|
60
|
+
export type { OAuthBearerOptions, OAuthResourceServer, ResolvedOAuthPrincipal, } from './bearer.js';
|
|
61
|
+
export { createRevocationService, REVOKED_BY_CLIENT, REVOKED_BY_USER, REVOKED_CLIENT_WIDE, } from './revocation-service.js';
|
|
62
|
+
export type { RevocationService, RevocationServiceOptions, RevokedGrant, } from './revocation-service.js';
|
|
63
|
+
export { createRevocationHandlers, createRevocationRouter, } from './revocation-controller.js';
|
|
64
|
+
export type { RevocationHandlerDeps, RevocationHandlers, RevocationRouterOptions, } from './revocation-controller.js';
|
|
65
|
+
export { createConnectionsHandlers, createConnectionsRouter, ACCOUNT_COVERAGE_STATEMENT, } from './connections-controller.js';
|
|
66
|
+
export type { ConnectionView, ConnectionsHandlers, ConnectionsHandlerDeps, ConnectionsRouterOptions, } from './connections-controller.js';
|
|
67
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @boopkit/cap-oauth-server — an OAuth 2.1 authorization server and resource
|
|
4
|
+
* server for a boop application.
|
|
5
|
+
*
|
|
6
|
+
* Slice 1 shipped the parts every later slice speaks in terms of: the client
|
|
7
|
+
* registry that knows who is asking, and the discovery documents that tell a
|
|
8
|
+
* client what we are. Slice 2 adds the grant itself — the consent screen, the
|
|
9
|
+
* authorization code, `POST /oauth/token`, and enough of a resource-server
|
|
10
|
+
* guard to make an authenticated call real. Slice 3 makes that guard something
|
|
11
|
+
* a route can defend itself with — `requireOAuth(...scopes)` and its RFC 6750
|
|
12
|
+
* refusals — adds soft revocation, and gives a person the two screens where
|
|
13
|
+
* they see and disconnect what they have connected.
|
|
14
|
+
*
|
|
15
|
+
* **The identity boundary.** Nothing in this package reaches a user, an
|
|
16
|
+
* account, or an identity except through `@boopkit/cap-users`' public surface.
|
|
17
|
+
* The one table it owns is `oauth_clients`, which describes software rather
|
|
18
|
+
* than people. `tests/packages/cap-oauth-server-import-audit.test.ts` enforces
|
|
19
|
+
* that mechanically.
|
|
20
|
+
*/
|
|
21
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
22
|
+
exports.OAUTH_REFRESH_DOMAIN = exports.OAUTH_ACCESS_DOMAIN = exports.OAUTH_CODE_DOMAIN = exports.AUTHORIZATION_CODE_TTL_SECONDS = exports.buildIdentityKey = exports.createTokenService = exports.CLIENT_MODES = exports.DEFAULT_REGISTRATION_RATE_WINDOW_MS = exports.DEFAULT_REGISTRATION_RATE_LIMIT = exports.createRegistrationRateLimiter = exports.toRegistrationResponse = exports.createRegistrationRouter = exports.createRegistrationHandlers = exports.createDiscoveryRouter = exports.createDiscoveryHandlers = exports.REFRESH_TOKEN_TTL_BOUNDS = exports.ACCESS_TOKEN_TTL_BOUNDS = exports.DEFAULT_REFRESH_TOKEN_TTL_SECONDS = exports.DEFAULT_ACCESS_TOKEN_TTL_SECONDS = exports.OauthServerConfigError = exports.clampTtlSeconds = exports.readServerConfig = exports.DISCOVERY_MAX_AGE_SECONDS = exports.DEFAULT_SCOPES_SUPPORTED = exports.DEVICE_CODE_GRANT_TYPE = exports.CODE_CHALLENGE_METHODS_SUPPORTED = exports.buildProtectedResourceMetadata = exports.buildAuthorizationServerMetadata = exports.DEFAULT_METADATA_MAX_REDIRECTS = exports.DEFAULT_METADATA_MAX_BYTES = exports.DEFAULT_METADATA_TIMEOUT_MS = exports.isValidMetadataUri = exports.fetchMetadataDocument = exports.DEFAULT_MAX_REGISTERED_CLIENTS = exports.DEFAULT_ABANDONED_CLIENT_TTL_MS = exports.DEFAULT_METADATA_MAX_AGE_MS = exports.DEFAULT_RESPONSE_TYPES = exports.DEFAULT_GRANT_TYPES = exports.validateRedirectUris = exports.createClientRegistryService = exports.isClientRegistryError = exports.ClientRegistryError = exports.CLIENT_PUBLIC_ID_LENGTH = exports.CLIENT_PUBLIC_ID_ALPHABET = exports.isValidClientPublicId = exports.generateClientPublicId = exports.isLoopbackHost = exports.matchesAnyRedirectUri = exports.matchRedirectUri = exports.classifyRedirectUri = void 0;
|
|
23
|
+
exports.ACCOUNT_COVERAGE_STATEMENT = exports.createConnectionsRouter = exports.createConnectionsHandlers = exports.createRevocationRouter = exports.createRevocationHandlers = exports.REVOKED_CLIENT_WIDE = exports.REVOKED_BY_USER = exports.REVOKED_BY_CLIENT = exports.createRevocationService = exports.DEFAULT_BEARER_CHALLENGE = exports.requireOAuth = exports.missingScopes = exports.createOAuthTokenResolver = exports.createOAuthResourceServer = exports.createOAuthBearerMiddleware = exports.OFFLINE_ACCESS_SCOPE = exports.parseScopes = exports.createTokenRouter = exports.createTokenHandlers = exports.SCOPE_DESCRIPTIONS_LOCAL = exports.warnUndescribedScopes = exports.toScopeViews = exports.scopeDescriptionsFrom = exports.safeLogoUri = exports.provenanceFor = exports.monogramFor = exports.createConsentRouter = exports.createConsentHandlers = exports.writeArray = exports.readArray = exports.isStaleWriteError = exports.isOAuthError = exports.OAuthError = exports.verifyCodeChallenge = exports.isValidCodeVerifier = exports.isValidCodeChallenge = exports.deriveCodeChallenge = exports.CODE_CHALLENGE_METHOD = exports.OAUTH_CODES_INFO_SCHEMA = exports.OAUTH_CODES_PROPERTY = exports.createAuthorizationCodeService = exports.OAUTH_GRANTS_INFO_SCHEMA = exports.OAUTH_GRANTS_PROPERTY = exports.isGrantActive = exports.createGrantService = void 0;
|
|
24
|
+
// Side-effect import: the Express request augmentation this capability's
|
|
25
|
+
// middleware writes (`req.oauthGrant`) and its consent controller reads
|
|
26
|
+
// (`req.user`). Importing the package is what gives an application those
|
|
27
|
+
// declarations. See `src/express.ts` for why they are re-declarations.
|
|
28
|
+
require("./express.js");
|
|
29
|
+
var redirect_uri_js_1 = require("./redirect-uri.js");
|
|
30
|
+
Object.defineProperty(exports, "classifyRedirectUri", { enumerable: true, get: function () { return redirect_uri_js_1.classifyRedirectUri; } });
|
|
31
|
+
Object.defineProperty(exports, "matchRedirectUri", { enumerable: true, get: function () { return redirect_uri_js_1.matchRedirectUri; } });
|
|
32
|
+
Object.defineProperty(exports, "matchesAnyRedirectUri", { enumerable: true, get: function () { return redirect_uri_js_1.matchesAnyRedirectUri; } });
|
|
33
|
+
Object.defineProperty(exports, "isLoopbackHost", { enumerable: true, get: function () { return redirect_uri_js_1.isLoopbackHost; } });
|
|
34
|
+
var public_id_js_1 = require("./public-id.js");
|
|
35
|
+
Object.defineProperty(exports, "generateClientPublicId", { enumerable: true, get: function () { return public_id_js_1.generateClientPublicId; } });
|
|
36
|
+
Object.defineProperty(exports, "isValidClientPublicId", { enumerable: true, get: function () { return public_id_js_1.isValidClientPublicId; } });
|
|
37
|
+
Object.defineProperty(exports, "CLIENT_PUBLIC_ID_ALPHABET", { enumerable: true, get: function () { return public_id_js_1.CLIENT_PUBLIC_ID_ALPHABET; } });
|
|
38
|
+
Object.defineProperty(exports, "CLIENT_PUBLIC_ID_LENGTH", { enumerable: true, get: function () { return public_id_js_1.CLIENT_PUBLIC_ID_LENGTH; } });
|
|
39
|
+
var errors_js_1 = require("./errors.js");
|
|
40
|
+
Object.defineProperty(exports, "ClientRegistryError", { enumerable: true, get: function () { return errors_js_1.ClientRegistryError; } });
|
|
41
|
+
Object.defineProperty(exports, "isClientRegistryError", { enumerable: true, get: function () { return errors_js_1.isClientRegistryError; } });
|
|
42
|
+
var client_registry_service_js_1 = require("./client-registry-service.js");
|
|
43
|
+
Object.defineProperty(exports, "createClientRegistryService", { enumerable: true, get: function () { return client_registry_service_js_1.createClientRegistryService; } });
|
|
44
|
+
Object.defineProperty(exports, "validateRedirectUris", { enumerable: true, get: function () { return client_registry_service_js_1.validateRedirectUris; } });
|
|
45
|
+
Object.defineProperty(exports, "DEFAULT_GRANT_TYPES", { enumerable: true, get: function () { return client_registry_service_js_1.DEFAULT_GRANT_TYPES; } });
|
|
46
|
+
Object.defineProperty(exports, "DEFAULT_RESPONSE_TYPES", { enumerable: true, get: function () { return client_registry_service_js_1.DEFAULT_RESPONSE_TYPES; } });
|
|
47
|
+
Object.defineProperty(exports, "DEFAULT_METADATA_MAX_AGE_MS", { enumerable: true, get: function () { return client_registry_service_js_1.DEFAULT_METADATA_MAX_AGE_MS; } });
|
|
48
|
+
Object.defineProperty(exports, "DEFAULT_ABANDONED_CLIENT_TTL_MS", { enumerable: true, get: function () { return client_registry_service_js_1.DEFAULT_ABANDONED_CLIENT_TTL_MS; } });
|
|
49
|
+
Object.defineProperty(exports, "DEFAULT_MAX_REGISTERED_CLIENTS", { enumerable: true, get: function () { return client_registry_service_js_1.DEFAULT_MAX_REGISTERED_CLIENTS; } });
|
|
50
|
+
var metadata_document_js_1 = require("./metadata-document.js");
|
|
51
|
+
Object.defineProperty(exports, "fetchMetadataDocument", { enumerable: true, get: function () { return metadata_document_js_1.fetchMetadataDocument; } });
|
|
52
|
+
Object.defineProperty(exports, "isValidMetadataUri", { enumerable: true, get: function () { return metadata_document_js_1.isValidMetadataUri; } });
|
|
53
|
+
Object.defineProperty(exports, "DEFAULT_METADATA_TIMEOUT_MS", { enumerable: true, get: function () { return metadata_document_js_1.DEFAULT_METADATA_TIMEOUT_MS; } });
|
|
54
|
+
Object.defineProperty(exports, "DEFAULT_METADATA_MAX_BYTES", { enumerable: true, get: function () { return metadata_document_js_1.DEFAULT_METADATA_MAX_BYTES; } });
|
|
55
|
+
Object.defineProperty(exports, "DEFAULT_METADATA_MAX_REDIRECTS", { enumerable: true, get: function () { return metadata_document_js_1.DEFAULT_METADATA_MAX_REDIRECTS; } });
|
|
56
|
+
var discovery_js_1 = require("./discovery.js");
|
|
57
|
+
Object.defineProperty(exports, "buildAuthorizationServerMetadata", { enumerable: true, get: function () { return discovery_js_1.buildAuthorizationServerMetadata; } });
|
|
58
|
+
Object.defineProperty(exports, "buildProtectedResourceMetadata", { enumerable: true, get: function () { return discovery_js_1.buildProtectedResourceMetadata; } });
|
|
59
|
+
Object.defineProperty(exports, "CODE_CHALLENGE_METHODS_SUPPORTED", { enumerable: true, get: function () { return discovery_js_1.CODE_CHALLENGE_METHODS_SUPPORTED; } });
|
|
60
|
+
Object.defineProperty(exports, "DEVICE_CODE_GRANT_TYPE", { enumerable: true, get: function () { return discovery_js_1.DEVICE_CODE_GRANT_TYPE; } });
|
|
61
|
+
Object.defineProperty(exports, "DEFAULT_SCOPES_SUPPORTED", { enumerable: true, get: function () { return discovery_js_1.DEFAULT_SCOPES_SUPPORTED; } });
|
|
62
|
+
Object.defineProperty(exports, "DISCOVERY_MAX_AGE_SECONDS", { enumerable: true, get: function () { return discovery_js_1.DISCOVERY_MAX_AGE_SECONDS; } });
|
|
63
|
+
var config_js_1 = require("./config.js");
|
|
64
|
+
Object.defineProperty(exports, "readServerConfig", { enumerable: true, get: function () { return config_js_1.readServerConfig; } });
|
|
65
|
+
Object.defineProperty(exports, "clampTtlSeconds", { enumerable: true, get: function () { return config_js_1.clampTtlSeconds; } });
|
|
66
|
+
Object.defineProperty(exports, "OauthServerConfigError", { enumerable: true, get: function () { return config_js_1.OauthServerConfigError; } });
|
|
67
|
+
Object.defineProperty(exports, "DEFAULT_ACCESS_TOKEN_TTL_SECONDS", { enumerable: true, get: function () { return config_js_1.DEFAULT_ACCESS_TOKEN_TTL_SECONDS; } });
|
|
68
|
+
Object.defineProperty(exports, "DEFAULT_REFRESH_TOKEN_TTL_SECONDS", { enumerable: true, get: function () { return config_js_1.DEFAULT_REFRESH_TOKEN_TTL_SECONDS; } });
|
|
69
|
+
Object.defineProperty(exports, "ACCESS_TOKEN_TTL_BOUNDS", { enumerable: true, get: function () { return config_js_1.ACCESS_TOKEN_TTL_BOUNDS; } });
|
|
70
|
+
Object.defineProperty(exports, "REFRESH_TOKEN_TTL_BOUNDS", { enumerable: true, get: function () { return config_js_1.REFRESH_TOKEN_TTL_BOUNDS; } });
|
|
71
|
+
var discovery_controller_js_1 = require("./discovery-controller.js");
|
|
72
|
+
Object.defineProperty(exports, "createDiscoveryHandlers", { enumerable: true, get: function () { return discovery_controller_js_1.createDiscoveryHandlers; } });
|
|
73
|
+
Object.defineProperty(exports, "createDiscoveryRouter", { enumerable: true, get: function () { return discovery_controller_js_1.createDiscoveryRouter; } });
|
|
74
|
+
var registration_controller_js_1 = require("./registration-controller.js");
|
|
75
|
+
Object.defineProperty(exports, "createRegistrationHandlers", { enumerable: true, get: function () { return registration_controller_js_1.createRegistrationHandlers; } });
|
|
76
|
+
Object.defineProperty(exports, "createRegistrationRouter", { enumerable: true, get: function () { return registration_controller_js_1.createRegistrationRouter; } });
|
|
77
|
+
Object.defineProperty(exports, "toRegistrationResponse", { enumerable: true, get: function () { return registration_controller_js_1.toRegistrationResponse; } });
|
|
78
|
+
var rate_limit_js_1 = require("./rate-limit.js");
|
|
79
|
+
Object.defineProperty(exports, "createRegistrationRateLimiter", { enumerable: true, get: function () { return rate_limit_js_1.createRegistrationRateLimiter; } });
|
|
80
|
+
Object.defineProperty(exports, "DEFAULT_REGISTRATION_RATE_LIMIT", { enumerable: true, get: function () { return rate_limit_js_1.DEFAULT_REGISTRATION_RATE_LIMIT; } });
|
|
81
|
+
Object.defineProperty(exports, "DEFAULT_REGISTRATION_RATE_WINDOW_MS", { enumerable: true, get: function () { return rate_limit_js_1.DEFAULT_REGISTRATION_RATE_WINDOW_MS; } });
|
|
82
|
+
var types_js_1 = require("./types.js");
|
|
83
|
+
Object.defineProperty(exports, "CLIENT_MODES", { enumerable: true, get: function () { return types_js_1.CLIENT_MODES; } });
|
|
84
|
+
var token_service_js_1 = require("./token-service.js");
|
|
85
|
+
Object.defineProperty(exports, "createTokenService", { enumerable: true, get: function () { return token_service_js_1.createTokenService; } });
|
|
86
|
+
Object.defineProperty(exports, "buildIdentityKey", { enumerable: true, get: function () { return token_service_js_1.buildIdentityKey; } });
|
|
87
|
+
Object.defineProperty(exports, "AUTHORIZATION_CODE_TTL_SECONDS", { enumerable: true, get: function () { return token_service_js_1.AUTHORIZATION_CODE_TTL_SECONDS; } });
|
|
88
|
+
Object.defineProperty(exports, "OAUTH_CODE_DOMAIN", { enumerable: true, get: function () { return token_service_js_1.OAUTH_CODE_DOMAIN; } });
|
|
89
|
+
Object.defineProperty(exports, "OAUTH_ACCESS_DOMAIN", { enumerable: true, get: function () { return token_service_js_1.OAUTH_ACCESS_DOMAIN; } });
|
|
90
|
+
Object.defineProperty(exports, "OAUTH_REFRESH_DOMAIN", { enumerable: true, get: function () { return token_service_js_1.OAUTH_REFRESH_DOMAIN; } });
|
|
91
|
+
var grant_service_js_1 = require("./grant-service.js");
|
|
92
|
+
Object.defineProperty(exports, "createGrantService", { enumerable: true, get: function () { return grant_service_js_1.createGrantService; } });
|
|
93
|
+
Object.defineProperty(exports, "isGrantActive", { enumerable: true, get: function () { return grant_service_js_1.isGrantActive; } });
|
|
94
|
+
Object.defineProperty(exports, "OAUTH_GRANTS_PROPERTY", { enumerable: true, get: function () { return grant_service_js_1.OAUTH_GRANTS_PROPERTY; } });
|
|
95
|
+
Object.defineProperty(exports, "OAUTH_GRANTS_INFO_SCHEMA", { enumerable: true, get: function () { return grant_service_js_1.OAUTH_GRANTS_INFO_SCHEMA; } });
|
|
96
|
+
var authorization_code_service_js_1 = require("./authorization-code-service.js");
|
|
97
|
+
Object.defineProperty(exports, "createAuthorizationCodeService", { enumerable: true, get: function () { return authorization_code_service_js_1.createAuthorizationCodeService; } });
|
|
98
|
+
Object.defineProperty(exports, "OAUTH_CODES_PROPERTY", { enumerable: true, get: function () { return authorization_code_service_js_1.OAUTH_CODES_PROPERTY; } });
|
|
99
|
+
Object.defineProperty(exports, "OAUTH_CODES_INFO_SCHEMA", { enumerable: true, get: function () { return authorization_code_service_js_1.OAUTH_CODES_INFO_SCHEMA; } });
|
|
100
|
+
var pkce_js_1 = require("./pkce.js");
|
|
101
|
+
Object.defineProperty(exports, "CODE_CHALLENGE_METHOD", { enumerable: true, get: function () { return pkce_js_1.CODE_CHALLENGE_METHOD; } });
|
|
102
|
+
Object.defineProperty(exports, "deriveCodeChallenge", { enumerable: true, get: function () { return pkce_js_1.deriveCodeChallenge; } });
|
|
103
|
+
Object.defineProperty(exports, "isValidCodeChallenge", { enumerable: true, get: function () { return pkce_js_1.isValidCodeChallenge; } });
|
|
104
|
+
Object.defineProperty(exports, "isValidCodeVerifier", { enumerable: true, get: function () { return pkce_js_1.isValidCodeVerifier; } });
|
|
105
|
+
Object.defineProperty(exports, "verifyCodeChallenge", { enumerable: true, get: function () { return pkce_js_1.verifyCodeChallenge; } });
|
|
106
|
+
var oauth_error_js_1 = require("./oauth-error.js");
|
|
107
|
+
Object.defineProperty(exports, "OAuthError", { enumerable: true, get: function () { return oauth_error_js_1.OAuthError; } });
|
|
108
|
+
Object.defineProperty(exports, "isOAuthError", { enumerable: true, get: function () { return oauth_error_js_1.isOAuthError; } });
|
|
109
|
+
var user_store_js_1 = require("./user-store.js");
|
|
110
|
+
Object.defineProperty(exports, "isStaleWriteError", { enumerable: true, get: function () { return user_store_js_1.isStaleWriteError; } });
|
|
111
|
+
var property_array_js_1 = require("./property-array.js");
|
|
112
|
+
Object.defineProperty(exports, "readArray", { enumerable: true, get: function () { return property_array_js_1.readArray; } });
|
|
113
|
+
Object.defineProperty(exports, "writeArray", { enumerable: true, get: function () { return property_array_js_1.writeArray; } });
|
|
114
|
+
var consent_controller_js_1 = require("./consent-controller.js");
|
|
115
|
+
Object.defineProperty(exports, "createConsentHandlers", { enumerable: true, get: function () { return consent_controller_js_1.createConsentHandlers; } });
|
|
116
|
+
Object.defineProperty(exports, "createConsentRouter", { enumerable: true, get: function () { return consent_controller_js_1.createConsentRouter; } });
|
|
117
|
+
Object.defineProperty(exports, "monogramFor", { enumerable: true, get: function () { return consent_controller_js_1.monogramFor; } });
|
|
118
|
+
Object.defineProperty(exports, "provenanceFor", { enumerable: true, get: function () { return consent_controller_js_1.provenanceFor; } });
|
|
119
|
+
Object.defineProperty(exports, "safeLogoUri", { enumerable: true, get: function () { return consent_controller_js_1.safeLogoUri; } });
|
|
120
|
+
Object.defineProperty(exports, "scopeDescriptionsFrom", { enumerable: true, get: function () { return consent_controller_js_1.scopeDescriptionsFrom; } });
|
|
121
|
+
Object.defineProperty(exports, "toScopeViews", { enumerable: true, get: function () { return consent_controller_js_1.toScopeViews; } });
|
|
122
|
+
Object.defineProperty(exports, "warnUndescribedScopes", { enumerable: true, get: function () { return consent_controller_js_1.warnUndescribedScopes; } });
|
|
123
|
+
Object.defineProperty(exports, "SCOPE_DESCRIPTIONS_LOCAL", { enumerable: true, get: function () { return consent_controller_js_1.SCOPE_DESCRIPTIONS_LOCAL; } });
|
|
124
|
+
var token_controller_js_1 = require("./token-controller.js");
|
|
125
|
+
Object.defineProperty(exports, "createTokenHandlers", { enumerable: true, get: function () { return token_controller_js_1.createTokenHandlers; } });
|
|
126
|
+
Object.defineProperty(exports, "createTokenRouter", { enumerable: true, get: function () { return token_controller_js_1.createTokenRouter; } });
|
|
127
|
+
Object.defineProperty(exports, "parseScopes", { enumerable: true, get: function () { return token_controller_js_1.parseScopes; } });
|
|
128
|
+
Object.defineProperty(exports, "OFFLINE_ACCESS_SCOPE", { enumerable: true, get: function () { return token_controller_js_1.OFFLINE_ACCESS_SCOPE; } });
|
|
129
|
+
var bearer_js_1 = require("./bearer.js");
|
|
130
|
+
Object.defineProperty(exports, "createOAuthBearerMiddleware", { enumerable: true, get: function () { return bearer_js_1.createOAuthBearerMiddleware; } });
|
|
131
|
+
Object.defineProperty(exports, "createOAuthResourceServer", { enumerable: true, get: function () { return bearer_js_1.createOAuthResourceServer; } });
|
|
132
|
+
Object.defineProperty(exports, "createOAuthTokenResolver", { enumerable: true, get: function () { return bearer_js_1.createOAuthTokenResolver; } });
|
|
133
|
+
Object.defineProperty(exports, "missingScopes", { enumerable: true, get: function () { return bearer_js_1.missingScopes; } });
|
|
134
|
+
Object.defineProperty(exports, "requireOAuth", { enumerable: true, get: function () { return bearer_js_1.requireOAuth; } });
|
|
135
|
+
Object.defineProperty(exports, "DEFAULT_BEARER_CHALLENGE", { enumerable: true, get: function () { return bearer_js_1.DEFAULT_BEARER_CHALLENGE; } });
|
|
136
|
+
var revocation_service_js_1 = require("./revocation-service.js");
|
|
137
|
+
Object.defineProperty(exports, "createRevocationService", { enumerable: true, get: function () { return revocation_service_js_1.createRevocationService; } });
|
|
138
|
+
Object.defineProperty(exports, "REVOKED_BY_CLIENT", { enumerable: true, get: function () { return revocation_service_js_1.REVOKED_BY_CLIENT; } });
|
|
139
|
+
Object.defineProperty(exports, "REVOKED_BY_USER", { enumerable: true, get: function () { return revocation_service_js_1.REVOKED_BY_USER; } });
|
|
140
|
+
Object.defineProperty(exports, "REVOKED_CLIENT_WIDE", { enumerable: true, get: function () { return revocation_service_js_1.REVOKED_CLIENT_WIDE; } });
|
|
141
|
+
var revocation_controller_js_1 = require("./revocation-controller.js");
|
|
142
|
+
Object.defineProperty(exports, "createRevocationHandlers", { enumerable: true, get: function () { return revocation_controller_js_1.createRevocationHandlers; } });
|
|
143
|
+
Object.defineProperty(exports, "createRevocationRouter", { enumerable: true, get: function () { return revocation_controller_js_1.createRevocationRouter; } });
|
|
144
|
+
var connections_controller_js_1 = require("./connections-controller.js");
|
|
145
|
+
Object.defineProperty(exports, "createConnectionsHandlers", { enumerable: true, get: function () { return connections_controller_js_1.createConnectionsHandlers; } });
|
|
146
|
+
Object.defineProperty(exports, "createConnectionsRouter", { enumerable: true, get: function () { return connections_controller_js_1.createConnectionsRouter; } });
|
|
147
|
+
Object.defineProperty(exports, "ACCOUNT_COVERAGE_STATEMENT", { enumerable: true, get: function () { return connections_controller_js_1.ACCOUNT_COVERAGE_STATEMENT; } });
|
|
148
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import type { ClientIdMetadataDocument } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Fetching a Client ID Metadata Document.
|
|
4
|
+
*
|
|
5
|
+
* A CIMD client's `client_id` *is* an `https` URL, and the document at that URL
|
|
6
|
+
* is the client's metadata. So this function reaches out to a host we do not
|
|
7
|
+
* control, on a path a stranger chose, during an authorization request a user
|
|
8
|
+
* is waiting on. Everything here is a bound on what that can cost or claim.
|
|
9
|
+
*
|
|
10
|
+
* The HTTP boundary is injected rather than imported, so the component tests
|
|
11
|
+
* drive it directly: what a failing fetch, an oversized body or a lying
|
|
12
|
+
* document do is behaviour worth pinning, and none of it is reachable through a
|
|
13
|
+
* real network in a test suite.
|
|
14
|
+
*/
|
|
15
|
+
/** The `fetch` shape this module needs. Narrower than the global on purpose. */
|
|
16
|
+
export type FetchLike = (url: string, init: {
|
|
17
|
+
method: string;
|
|
18
|
+
redirect: 'manual';
|
|
19
|
+
signal: AbortSignal;
|
|
20
|
+
headers: Record<string, string>;
|
|
21
|
+
}) => Promise<FetchLikeResponse>;
|
|
22
|
+
export interface FetchLikeResponse {
|
|
23
|
+
status: number;
|
|
24
|
+
headers: {
|
|
25
|
+
get(name: string): string | null;
|
|
26
|
+
};
|
|
27
|
+
text(): Promise<string>;
|
|
28
|
+
}
|
|
29
|
+
export interface MetadataFetchOptions {
|
|
30
|
+
/**
|
|
31
|
+
* Three seconds, well inside Claude's ten-second budget for the whole
|
|
32
|
+
* authorization step. The user is on the consent redirect while this runs.
|
|
33
|
+
*/
|
|
34
|
+
timeoutMs?: number;
|
|
35
|
+
/** Bytes. A metadata document is a few hundred; 64 KiB is generous. */
|
|
36
|
+
maxBytes?: number;
|
|
37
|
+
/** How many `https`→`https` hops to follow before giving up. */
|
|
38
|
+
maxRedirects?: number;
|
|
39
|
+
}
|
|
40
|
+
export declare const DEFAULT_METADATA_TIMEOUT_MS = 3000;
|
|
41
|
+
export declare const DEFAULT_METADATA_MAX_BYTES: number;
|
|
42
|
+
export declare const DEFAULT_METADATA_MAX_REDIRECTS = 3;
|
|
43
|
+
/**
|
|
44
|
+
* Is this a URL we are willing to treat as a `client_id`?
|
|
45
|
+
*
|
|
46
|
+
* `https` only, no credentials, no fragment. The fragment rule matters because
|
|
47
|
+
* `client_id` is compared for equality against the document's own `client_id`,
|
|
48
|
+
* and two URLs differing only in fragment address the same document while
|
|
49
|
+
* comparing unequal — an ambiguity a registry key cannot afford.
|
|
50
|
+
*/
|
|
51
|
+
export declare function isValidMetadataUri(value: string): boolean;
|
|
52
|
+
/**
|
|
53
|
+
* Fetch and parse the document at `clientId`.
|
|
54
|
+
*
|
|
55
|
+
* Throws `ClientRegistryError('boop_metadata_document_unusable')` for every
|
|
56
|
+
* failure, so the caller has one thing to catch and one decision to make: fall
|
|
57
|
+
* back to a cached copy, or fail the request.
|
|
58
|
+
*/
|
|
59
|
+
export declare function fetchMetadataDocument(clientId: string, fetchImpl: FetchLike, options?: MetadataFetchOptions): Promise<ClientIdMetadataDocument>;
|
|
60
|
+
//# sourceMappingURL=metadata-document.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metadata-document.d.ts","sourceRoot":"","sources":["../src/metadata-document.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAC;AAE3D;;;;;;;;;;;;GAYG;AAEH,gFAAgF;AAChF,MAAM,MAAM,SAAS,GAAG,CACtB,GAAG,EAAE,MAAM,EACX,IAAI,EAAE;IACJ,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,QAAQ,CAAC;IACnB,MAAM,EAAE,WAAW,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACjC,KACE,OAAO,CAAC,iBAAiB,CAAC,CAAC;AAEhC,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE;QAAE,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC;IAC9C,IAAI,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;CACzB;AAED,MAAM,WAAW,oBAAoB;IACnC;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,uEAAuE;IACvE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,gEAAgE;IAChE,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,eAAO,MAAM,2BAA2B,OAAQ,CAAC;AACjD,eAAO,MAAM,0BAA0B,QAAY,CAAC;AACpD,eAAO,MAAM,8BAA8B,IAAI,CAAC;AAKhD;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAczD;AAED;;;;;;GAMG;AACH,wBAAsB,qBAAqB,CACzC,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,SAAS,EACpB,OAAO,GAAE,oBAAyB,GACjC,OAAO,CAAC,wBAAwB,CAAC,CA+CnC"}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DEFAULT_METADATA_MAX_REDIRECTS = exports.DEFAULT_METADATA_MAX_BYTES = exports.DEFAULT_METADATA_TIMEOUT_MS = void 0;
|
|
4
|
+
exports.isValidMetadataUri = isValidMetadataUri;
|
|
5
|
+
exports.fetchMetadataDocument = fetchMetadataDocument;
|
|
6
|
+
const errors_js_1 = require("./errors.js");
|
|
7
|
+
exports.DEFAULT_METADATA_TIMEOUT_MS = 3000;
|
|
8
|
+
exports.DEFAULT_METADATA_MAX_BYTES = 64 * 1024;
|
|
9
|
+
exports.DEFAULT_METADATA_MAX_REDIRECTS = 3;
|
|
10
|
+
const unusable = (message) => new errors_js_1.ClientRegistryError('boop_metadata_document_unusable', message);
|
|
11
|
+
/**
|
|
12
|
+
* Is this a URL we are willing to treat as a `client_id`?
|
|
13
|
+
*
|
|
14
|
+
* `https` only, no credentials, no fragment. The fragment rule matters because
|
|
15
|
+
* `client_id` is compared for equality against the document's own `client_id`,
|
|
16
|
+
* and two URLs differing only in fragment address the same document while
|
|
17
|
+
* comparing unequal — an ambiguity a registry key cannot afford.
|
|
18
|
+
*/
|
|
19
|
+
function isValidMetadataUri(value) {
|
|
20
|
+
let url;
|
|
21
|
+
try {
|
|
22
|
+
url = new URL(value);
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
return (url.protocol === 'https:' &&
|
|
28
|
+
url.hostname !== '' &&
|
|
29
|
+
url.username === '' &&
|
|
30
|
+
url.password === '' &&
|
|
31
|
+
url.hash === '');
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Fetch and parse the document at `clientId`.
|
|
35
|
+
*
|
|
36
|
+
* Throws `ClientRegistryError('boop_metadata_document_unusable')` for every
|
|
37
|
+
* failure, so the caller has one thing to catch and one decision to make: fall
|
|
38
|
+
* back to a cached copy, or fail the request.
|
|
39
|
+
*/
|
|
40
|
+
async function fetchMetadataDocument(clientId, fetchImpl, options = {}) {
|
|
41
|
+
const timeoutMs = options.timeoutMs ?? exports.DEFAULT_METADATA_TIMEOUT_MS;
|
|
42
|
+
const maxBytes = options.maxBytes ?? exports.DEFAULT_METADATA_MAX_BYTES;
|
|
43
|
+
const maxRedirects = options.maxRedirects ?? exports.DEFAULT_METADATA_MAX_REDIRECTS;
|
|
44
|
+
if (!isValidMetadataUri(clientId)) {
|
|
45
|
+
throw unusable(`client_id is not a usable https metadata document URL: ${clientId}`);
|
|
46
|
+
}
|
|
47
|
+
const body = await readDocument(clientId, fetchImpl, { timeoutMs, maxBytes, maxRedirects });
|
|
48
|
+
let parsed;
|
|
49
|
+
try {
|
|
50
|
+
parsed = JSON.parse(body);
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
throw unusable(`metadata document at ${clientId} is not JSON`);
|
|
54
|
+
}
|
|
55
|
+
if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {
|
|
56
|
+
throw unusable(`metadata document at ${clientId} is not a JSON object`);
|
|
57
|
+
}
|
|
58
|
+
const doc = parsed;
|
|
59
|
+
/**
|
|
60
|
+
* **The check that stops one document claiming another's identity.**
|
|
61
|
+
*
|
|
62
|
+
* Without it, anyone who can publish a redirect — or simply a document — can
|
|
63
|
+
* assert someone else's `client_id`, and the consent screen then shows a name
|
|
64
|
+
* and logo belonging to a client the user trusts while the redirect goes
|
|
65
|
+
* somewhere else entirely.
|
|
66
|
+
*
|
|
67
|
+
* It is deliberately compared against the URL we were *asked* for rather than
|
|
68
|
+
* the URL we ended up at. That is the stricter reading: if `a.example`
|
|
69
|
+
* redirects to a document whose `client_id` is `b.example`, then following
|
|
70
|
+
* the redirect and accepting `b.example`'s claim would let the owner of
|
|
71
|
+
* `a.example` register under `b.example`'s identity. Requiring the document
|
|
72
|
+
* to name the URL the client presented closes that, and costs a CIMD
|
|
73
|
+
* publisher nothing — the specification already requires the document's
|
|
74
|
+
* `client_id` to be its own URL.
|
|
75
|
+
*/
|
|
76
|
+
if (doc.client_id !== clientId) {
|
|
77
|
+
throw unusable(`metadata document at ${clientId} claims a different client_id (${String(doc.client_id)})`);
|
|
78
|
+
}
|
|
79
|
+
return doc;
|
|
80
|
+
}
|
|
81
|
+
/** The transport half: redirects, timeout, size cap. */
|
|
82
|
+
async function readDocument(startUrl, fetchImpl, limits) {
|
|
83
|
+
let url = startUrl;
|
|
84
|
+
for (let hop = 0; hop <= limits.maxRedirects; hop += 1) {
|
|
85
|
+
const controller = new AbortController();
|
|
86
|
+
const timer = setTimeout(() => controller.abort(), limits.timeoutMs);
|
|
87
|
+
let response;
|
|
88
|
+
try {
|
|
89
|
+
response = await fetchImpl(url, {
|
|
90
|
+
method: 'GET',
|
|
91
|
+
// Manual, so a redirect is a decision this code makes rather than one
|
|
92
|
+
// the HTTP client makes for it. `fetch`'s own redirect following would
|
|
93
|
+
// happily walk `https` → `http`, which is the hop this refuses.
|
|
94
|
+
redirect: 'manual',
|
|
95
|
+
signal: controller.signal,
|
|
96
|
+
headers: { accept: 'application/json' },
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
catch (err) {
|
|
100
|
+
throw unusable(`metadata document at ${url} could not be fetched: ${describe(err)}`);
|
|
101
|
+
}
|
|
102
|
+
finally {
|
|
103
|
+
clearTimeout(timer);
|
|
104
|
+
}
|
|
105
|
+
if (response.status >= 300 && response.status < 400) {
|
|
106
|
+
const location = response.headers.get('location');
|
|
107
|
+
if (!location)
|
|
108
|
+
throw unusable(`metadata document at ${url} redirected with no Location`);
|
|
109
|
+
let next;
|
|
110
|
+
try {
|
|
111
|
+
next = new URL(location, url);
|
|
112
|
+
}
|
|
113
|
+
catch {
|
|
114
|
+
throw unusable(`metadata document at ${url} redirected to an unparseable ${location}`);
|
|
115
|
+
}
|
|
116
|
+
if (next.protocol !== 'https:') {
|
|
117
|
+
throw unusable(`metadata document at ${url} redirected to a non-https origin (${next.protocol}//${next.host})`);
|
|
118
|
+
}
|
|
119
|
+
url = next.toString();
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
122
|
+
if (response.status !== 200) {
|
|
123
|
+
throw unusable(`metadata document at ${url} answered ${response.status}`);
|
|
124
|
+
}
|
|
125
|
+
// Two size checks, because either alone has a hole. A declared
|
|
126
|
+
// `content-length` refuses a large body before it is read; measuring the
|
|
127
|
+
// body afterwards catches a chunked response that declared nothing. Neither
|
|
128
|
+
// caps the bytes actually pulled over the wire — that would need a stream,
|
|
129
|
+
// and `fetch`'s body is one, but the injected boundary these tests drive is
|
|
130
|
+
// not. The timeout is what bounds the pathological case in the meantime.
|
|
131
|
+
const declared = Number(response.headers.get('content-length'));
|
|
132
|
+
if (Number.isFinite(declared) && declared > limits.maxBytes) {
|
|
133
|
+
throw unusable(`metadata document at ${url} declares ${declared} bytes, over the ${limits.maxBytes} cap`);
|
|
134
|
+
}
|
|
135
|
+
const text = await response.text();
|
|
136
|
+
if (Buffer.byteLength(text, 'utf8') > limits.maxBytes) {
|
|
137
|
+
throw unusable(`metadata document at ${url} is over the ${limits.maxBytes}-byte cap`);
|
|
138
|
+
}
|
|
139
|
+
return text;
|
|
140
|
+
}
|
|
141
|
+
throw unusable(`metadata document at ${startUrl} redirected more than ${limits.maxRedirects} times`);
|
|
142
|
+
}
|
|
143
|
+
function describe(err) {
|
|
144
|
+
if (err instanceof Error)
|
|
145
|
+
return err.message;
|
|
146
|
+
return String(err);
|
|
147
|
+
}
|
|
148
|
+
//# sourceMappingURL=metadata-document.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metadata-document.js","sourceRoot":"","sources":["../src/metadata-document.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RFC 6749 error responses, as a typed refusal the controllers translate once.
|
|
3
|
+
*
|
|
4
|
+
* ## Why this is separate from `ClientRegistryError`
|
|
5
|
+
*
|
|
6
|
+
* `errors.ts` carries registration's vocabulary — RFC 7591 §3.2.2 plus a few
|
|
7
|
+
* `boop_` codes for things the specification has no word for. This carries the
|
|
8
|
+
* *grant* vocabulary: RFC 6749 §5.2's five codes, which a client library parses
|
|
9
|
+
* and branches on. They are different registries with different consumers, and
|
|
10
|
+
* a single enum spanning both would let a registration code reach a token
|
|
11
|
+
* response, which no client knows how to read.
|
|
12
|
+
*
|
|
13
|
+
* ## Status codes are not free choices
|
|
14
|
+
*
|
|
15
|
+
* §5.2 fixes them. `invalid_client` is 401 (with a `WWW-Authenticate` header
|
|
16
|
+
* when the client tried to authenticate); everything else is 400. Answering
|
|
17
|
+
* `invalid_grant` with a 401 makes a well-written client discard its refresh
|
|
18
|
+
* token *and* its access token and start a whole new authorization, which is a
|
|
19
|
+
* user-visible re-consent for what may be a transient server fault.
|
|
20
|
+
*/
|
|
21
|
+
/**
|
|
22
|
+
* RFC 6749 §5.2, plus §4.1.2.1's `access_denied` for the authorize redirect and
|
|
23
|
+
* RFC 7009 §2.2.1's `unsupported_token_type` for the revocation endpoint.
|
|
24
|
+
*
|
|
25
|
+
* `unsupported_token_type` belongs here rather than in `errors.ts` for the same
|
|
26
|
+
* reason the rest of this list does: RFC 7009 registers it in the OAuth
|
|
27
|
+
* Extensions Error Registry the token endpoint draws from, and a client library
|
|
28
|
+
* parses it off a body of exactly this shape. Its status is the default 400, so
|
|
29
|
+
* `STATUS_BY_CODE` needs no entry for it.
|
|
30
|
+
*/
|
|
31
|
+
export type OAuthErrorCode = 'invalid_request' | 'invalid_client' | 'invalid_grant' | 'unauthorized_client' | 'unsupported_grant_type' | 'unsupported_token_type' | 'invalid_scope' | 'access_denied' | 'server_error' | 'temporarily_unavailable' | 'unsupported_response_type';
|
|
32
|
+
export declare class OAuthError extends Error {
|
|
33
|
+
readonly error: OAuthErrorCode;
|
|
34
|
+
readonly status: number;
|
|
35
|
+
readonly description: string;
|
|
36
|
+
constructor(error: OAuthErrorCode, description: string, status?: number);
|
|
37
|
+
/** The response body, exactly as §5.2 shapes it. */
|
|
38
|
+
toBody(): {
|
|
39
|
+
error: OAuthErrorCode;
|
|
40
|
+
error_description: string;
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
/** Narrower than `instanceof`, which is a false negative across module copies. */
|
|
44
|
+
export declare function isOAuthError(err: unknown): err is OAuthError;
|
|
45
|
+
//# sourceMappingURL=oauth-error.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oauth-error.d.ts","sourceRoot":"","sources":["../src/oauth-error.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH;;;;;;;;;GASG;AACH,MAAM,MAAM,cAAc,GACtB,iBAAiB,GACjB,gBAAgB,GAChB,eAAe,GACf,qBAAqB,GACrB,wBAAwB,GACxB,wBAAwB,GACxB,eAAe,GACf,eAAe,GACf,cAAc,GACd,yBAAyB,GACzB,2BAA2B,CAAC;AAQhC,qBAAa,UAAW,SAAQ,KAAK;IACnC,QAAQ,CAAC,KAAK,EAAE,cAAc,CAAC;IAC/B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;gBAEjB,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM;IAQvE,oDAAoD;IACpD,MAAM,IAAI;QAAE,KAAK,EAAE,cAAc,CAAC;QAAC,iBAAiB,EAAE,MAAM,CAAA;KAAE;CAG/D;AAED,kFAAkF;AAClF,wBAAgB,YAAY,CAAC,GAAG,EAAE,OAAO,GAAG,GAAG,IAAI,UAAU,CAO5D"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* RFC 6749 error responses, as a typed refusal the controllers translate once.
|
|
4
|
+
*
|
|
5
|
+
* ## Why this is separate from `ClientRegistryError`
|
|
6
|
+
*
|
|
7
|
+
* `errors.ts` carries registration's vocabulary — RFC 7591 §3.2.2 plus a few
|
|
8
|
+
* `boop_` codes for things the specification has no word for. This carries the
|
|
9
|
+
* *grant* vocabulary: RFC 6749 §5.2's five codes, which a client library parses
|
|
10
|
+
* and branches on. They are different registries with different consumers, and
|
|
11
|
+
* a single enum spanning both would let a registration code reach a token
|
|
12
|
+
* response, which no client knows how to read.
|
|
13
|
+
*
|
|
14
|
+
* ## Status codes are not free choices
|
|
15
|
+
*
|
|
16
|
+
* §5.2 fixes them. `invalid_client` is 401 (with a `WWW-Authenticate` header
|
|
17
|
+
* when the client tried to authenticate); everything else is 400. Answering
|
|
18
|
+
* `invalid_grant` with a 401 makes a well-written client discard its refresh
|
|
19
|
+
* token *and* its access token and start a whole new authorization, which is a
|
|
20
|
+
* user-visible re-consent for what may be a transient server fault.
|
|
21
|
+
*/
|
|
22
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
23
|
+
exports.OAuthError = void 0;
|
|
24
|
+
exports.isOAuthError = isOAuthError;
|
|
25
|
+
const STATUS_BY_CODE = {
|
|
26
|
+
invalid_client: 401,
|
|
27
|
+
server_error: 500,
|
|
28
|
+
temporarily_unavailable: 503,
|
|
29
|
+
};
|
|
30
|
+
class OAuthError extends Error {
|
|
31
|
+
constructor(error, description, status) {
|
|
32
|
+
super(`${error}: ${description}`);
|
|
33
|
+
this.name = 'OAuthError';
|
|
34
|
+
this.error = error;
|
|
35
|
+
this.description = description;
|
|
36
|
+
this.status = status ?? STATUS_BY_CODE[error] ?? 400;
|
|
37
|
+
}
|
|
38
|
+
/** The response body, exactly as §5.2 shapes it. */
|
|
39
|
+
toBody() {
|
|
40
|
+
return { error: this.error, error_description: this.description };
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
exports.OAuthError = OAuthError;
|
|
44
|
+
/** Narrower than `instanceof`, which is a false negative across module copies. */
|
|
45
|
+
function isOAuthError(err) {
|
|
46
|
+
return (typeof err === 'object' &&
|
|
47
|
+
err !== null &&
|
|
48
|
+
err.name === 'OAuthError' &&
|
|
49
|
+
typeof err.error === 'string');
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=oauth-error.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oauth-error.js","sourceRoot":"","sources":["../src/oauth-error.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;GAmBG;;;AAmDH,oCAOC;AAjCD,MAAM,cAAc,GAA4C;IAC9D,cAAc,EAAE,GAAG;IACnB,YAAY,EAAE,GAAG;IACjB,uBAAuB,EAAE,GAAG;CAC7B,CAAC;AAEF,MAAa,UAAW,SAAQ,KAAK;IAKnC,YAAY,KAAqB,EAAE,WAAmB,EAAE,MAAe;QACrE,KAAK,CAAC,GAAG,KAAK,KAAK,WAAW,EAAE,CAAC,CAAC;QAClC,IAAI,CAAC,IAAI,GAAG,YAAY,CAAC;QACzB,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,WAAW,GAAG,WAAW,CAAC;QAC/B,IAAI,CAAC,MAAM,GAAG,MAAM,IAAI,cAAc,CAAC,KAAK,CAAC,IAAI,GAAG,CAAC;IACvD,CAAC;IAED,oDAAoD;IACpD,MAAM;QACJ,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,iBAAiB,EAAE,IAAI,CAAC,WAAW,EAAE,CAAC;IACpE,CAAC;CACF;AAjBD,gCAiBC;AAED,kFAAkF;AAClF,SAAgB,YAAY,CAAC,GAAY;IACvC,OAAO,CACL,OAAO,GAAG,KAAK,QAAQ;QACvB,GAAG,KAAK,IAAI;QACX,GAA0B,CAAC,IAAI,KAAK,YAAY;QACjD,OAAQ,GAA2B,CAAC,KAAK,KAAK,QAAQ,CACvD,CAAC;AACJ,CAAC"}
|
package/dist/pkce.d.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PKCE, RFC 7636 — and only `S256`.
|
|
3
|
+
*
|
|
4
|
+
* `plain` is not a weaker method, it is the absence of one: the "challenge" is
|
|
5
|
+
* the verifier, so an attacker who intercepted the authorization response has
|
|
6
|
+
* everything needed to redeem the code. The discovery document advertises
|
|
7
|
+
* `["S256"]` and this module is the other half of that promise — a request
|
|
8
|
+
* carrying `code_challenge_method=plain` is refused rather than downgraded to.
|
|
9
|
+
*
|
|
10
|
+
* OAuth 2.1 requires PKCE for public clients, and every client this server will
|
|
11
|
+
* ever see is public, so the challenge is **required** rather than optional.
|
|
12
|
+
*/
|
|
13
|
+
/** The only method this server accepts. Matches the discovery document. */
|
|
14
|
+
export declare const CODE_CHALLENGE_METHOD = "S256";
|
|
15
|
+
export declare function isValidCodeVerifier(value: unknown): value is string;
|
|
16
|
+
export declare function isValidCodeChallenge(value: unknown): value is string;
|
|
17
|
+
/** BASE64URL-ENCODE(SHA256(ASCII(verifier))), per RFC 7636 §4.6. */
|
|
18
|
+
export declare function deriveCodeChallenge(verifier: string): string;
|
|
19
|
+
/**
|
|
20
|
+
* Does `verifier` satisfy the `challenge` the authorization request carried?
|
|
21
|
+
*
|
|
22
|
+
* Compared with `timingSafeEqual` rather than `===`. The challenge is not a
|
|
23
|
+
* secret — it travelled in a query string — but the comparison is on the
|
|
24
|
+
* redemption path next to comparisons that are, and a codebase where one string
|
|
25
|
+
* equality is constant-time and its neighbour is not teaches the wrong habit to
|
|
26
|
+
* whoever writes the third one.
|
|
27
|
+
*/
|
|
28
|
+
export declare function verifyCodeChallenge(verifier: unknown, challenge: unknown, method?: unknown): boolean;
|
|
29
|
+
//# sourceMappingURL=pkce.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pkce.d.ts","sourceRoot":"","sources":["../src/pkce.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;GAWG;AAEH,2EAA2E;AAC3E,eAAO,MAAM,qBAAqB,SAAS,CAAC;AAc5C,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAEnE;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAEpE;AAED,oEAAoE;AACpE,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAE5D;AAED;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,OAAO,EACjB,SAAS,EAAE,OAAO,EAClB,MAAM,GAAE,OAA+B,GACtC,OAAO,CAST"}
|