Pass through rate limits and other options cleanly from router
This commit is contained in:
parent
1415c2db92
commit
48cddd9488
1 changed files with 48 additions and 25 deletions
|
|
@ -4,38 +4,43 @@ import { tokenHandler, TokenHandlerOptions } from "./handlers/token.js";
|
|||
import { authorizationHandler, AuthorizationHandlerOptions } from "./handlers/authorize.js";
|
||||
import { revocationHandler, RevocationHandlerOptions } from "./handlers/revoke.js";
|
||||
import { metadataHandler } from "./handlers/metadata.js";
|
||||
import { OAuthServerProvider } from "./provider.js";
|
||||
|
||||
export type MetadataOptions = {
|
||||
metadata: {
|
||||
/**
|
||||
* The authorization server's issuer identifier, which is a URL that uses the "https" scheme and has no query or fragment components.
|
||||
*/
|
||||
issuerUrl: URL;
|
||||
export type AuthRouterOptions = {
|
||||
/**
|
||||
* A provider implementing the actual authorization logic for this router.
|
||||
*/
|
||||
provider: OAuthServerProvider;
|
||||
|
||||
/**
|
||||
* An optional URL of a page containing human-readable information that developers might want or need to know when using the authorization server.
|
||||
*/
|
||||
serviceDocumentationUrl?: URL;
|
||||
};
|
||||
/**
|
||||
* The authorization server's issuer identifier, which is a URL that uses the "https" scheme and has no query or fragment components.
|
||||
*/
|
||||
issuerUrl: URL;
|
||||
|
||||
/**
|
||||
* An optional URL of a page containing human-readable information that developers might want or need to know when using the authorization server.
|
||||
*/
|
||||
serviceDocumentationUrl?: URL;
|
||||
|
||||
// Individual options per route
|
||||
authorizationOptions?: Omit<AuthorizationHandlerOptions, "provider">;
|
||||
clientRegistrationOptions?: Omit<ClientRegistrationHandlerOptions, "clientsStore">;
|
||||
revocationOptions?: Omit<RevocationHandlerOptions, "provider">;
|
||||
tokenOptions?: Omit<TokenHandlerOptions, "provider">;
|
||||
};
|
||||
|
||||
export type AuthRouterOptions =
|
||||
& AuthorizationHandlerOptions
|
||||
& Omit<ClientRegistrationHandlerOptions, "clientsStore">
|
||||
& MetadataOptions
|
||||
& RevocationHandlerOptions
|
||||
& TokenHandlerOptions;
|
||||
|
||||
/**
|
||||
* Installs standard MCP authorization endpoints, including dynamic client registration and token revocation (if supported). Also advertises standard authorization server metadata, for easier discovery of supported configurations by clients.
|
||||
*
|
||||
* By default, rate limiting is applied to all endpoints to prevent abuse.
|
||||
*
|
||||
* This router MUST be installed at the application root, like so:
|
||||
*
|
||||
* const app = express();
|
||||
* app.use(mcpAuthRouter(...));
|
||||
*/
|
||||
export function mcpAuthRouter(options: AuthRouterOptions): RequestHandler {
|
||||
const issuer = options.metadata.issuerUrl;
|
||||
const issuer = options.issuerUrl;
|
||||
|
||||
// Technically RFC 8414 does not permit a localhost HTTPS exemption, but this will be necessary for ease of testing
|
||||
if (issuer.protocol !== "https:" && issuer.hostname !== "localhost" && issuer.hostname !== "127.0.0.1") {
|
||||
|
|
@ -55,7 +60,7 @@ export function mcpAuthRouter(options: AuthRouterOptions): RequestHandler {
|
|||
|
||||
const metadata = {
|
||||
issuer: issuer.href,
|
||||
service_documentation: options.metadata.serviceDocumentationUrl?.href,
|
||||
service_documentation: options.serviceDocumentationUrl?.href,
|
||||
|
||||
authorization_endpoint: new URL(authorization_endpoint, issuer).href,
|
||||
response_types_supported: ["code"],
|
||||
|
|
@ -72,16 +77,34 @@ export function mcpAuthRouter(options: AuthRouterOptions): RequestHandler {
|
|||
};
|
||||
|
||||
const router = express.Router();
|
||||
router.use(authorization_endpoint, authorizationHandler(options));
|
||||
router.use(token_endpoint, tokenHandler(options));
|
||||
|
||||
router.use(
|
||||
authorization_endpoint,
|
||||
authorizationHandler({ provider: options.provider, ...options.authorizationOptions })
|
||||
);
|
||||
|
||||
router.use(
|
||||
token_endpoint,
|
||||
tokenHandler({ provider: options.provider, ...options.tokenOptions })
|
||||
);
|
||||
|
||||
router.use("/.well-known/oauth-authorization-server", metadataHandler(metadata));
|
||||
|
||||
if (registration_endpoint) {
|
||||
router.use(registration_endpoint, clientRegistrationHandler({ clientsStore: options.provider.clientsStore, ...options }));
|
||||
router.use(
|
||||
registration_endpoint,
|
||||
clientRegistrationHandler({
|
||||
clientsStore: options.provider.clientsStore,
|
||||
...options,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
if (revocation_endpoint) {
|
||||
router.use(revocation_endpoint, revocationHandler(options));
|
||||
router.use(
|
||||
revocation_endpoint,
|
||||
revocationHandler({ provider: options.provider, ...options.revocationOptions })
|
||||
);
|
||||
}
|
||||
|
||||
return router;
|
||||
|
|
|
|||
Loading…
Reference in a new issue