@@ -2,46 +2,69 @@ import { Request, Response } from "express";
22import { OAuthClientInformationFull , OAuthClientMetadataSchema , OAuthClientRegistrationError } from "../../../shared/auth.js" ;
33import crypto from 'node:crypto' ;
44import bodyParser from 'body-parser' ;
5+ import { OAuthRegisteredClientsStore } from "../clients.js" ;
56
6- async function handler ( requestBody : unknown ) : Promise < OAuthClientInformationFull | OAuthClientRegistrationError > {
7- let clientMetadata ;
8- try {
9- clientMetadata = OAuthClientMetadataSchema . parse ( requestBody ) ;
10- } catch ( error ) {
11- return { error : "invalid_client_metadata" , error_description : String ( error ) } ;
7+ export type ClientRegistrationHandlerOptions = {
8+ /**
9+ * A store used to save information about dynamically registered OAuth clients.
10+ */
11+ store : OAuthRegisteredClientsStore ;
12+
13+ /**
14+ * The number of seconds after which to expire issued client secrets, or 0 to prevent expiration of client secrets (not recommended).
15+ *
16+ * If not set, defaults to 30 days.
17+ */
18+ clientSecretExpirySeconds ?: number ;
19+ } ;
20+
21+ const DEFAULT_CLIENT_SECRET_EXPIRY_SECONDS = 30 * 24 * 60 * 60 ; // 30 days
22+
23+ export function clientRegistrationHandler ( { store, clientSecretExpirySeconds = DEFAULT_CLIENT_SECRET_EXPIRY_SECONDS } : ClientRegistrationHandlerOptions ) {
24+ if ( ! store . registerClient ) {
25+ throw new Error ( "Client registration store does not support registering clients" ) ;
1226 }
1327
14- // Implement RFC 7591 dynamic client registration
15- const clientId = crypto . randomUUID ( ) ;
16- const clientSecret = clientMetadata . token_endpoint_auth_method !== 'none'
17- ? crypto . randomBytes ( 32 ) . toString ( 'hex' )
18- : undefined ;
19- const clientIdIssuedAt = Math . floor ( Date . now ( ) / 1000 ) ;
20-
21- const clientInfo : OAuthClientInformationFull = {
22- ...clientMetadata ,
23- client_id : clientId ,
24- client_secret : clientSecret ,
25- client_id_issued_at : clientIdIssuedAt ,
26- client_secret_expires_at : 0 // Set to 0 for non-expiring secret
27- } ;
28-
29- // TODO: Store client information securely
30-
31- return clientInfo ;
32- }
33-
34- export const clientRegistrationHandler = ( req : Request , res : Response ) => bodyParser . json ( ) ( req , res , ( err ) => {
35- if ( err === undefined ) {
36- handler ( req . body ) . then ( ( result ) => {
37- if ( "error" in result ) {
38- res . status ( 400 ) . json ( result ) ;
39- } else {
40- res . status ( 201 ) . json ( result ) ;
41- }
42- } , ( error ) => {
43- console . error ( "Uncaught error in client registration handler:" , error ) ;
44- res . status ( 500 ) . end ( "Internal Server Error" ) ;
45- } ) ;
28+ async function register ( requestBody : unknown ) : Promise < OAuthClientInformationFull | OAuthClientRegistrationError > {
29+ let clientMetadata ;
30+ try {
31+ clientMetadata = OAuthClientMetadataSchema . parse ( requestBody ) ;
32+ } catch ( error ) {
33+ return { error : "invalid_client_metadata" , error_description : String ( error ) } ;
34+ }
35+
36+ // Implement RFC 7591 dynamic client registration
37+ const clientId = crypto . randomUUID ( ) ;
38+ const clientSecret = clientMetadata . token_endpoint_auth_method !== 'none'
39+ ? crypto . randomBytes ( 32 ) . toString ( 'hex' )
40+ : undefined ;
41+ const clientIdIssuedAt = Math . floor ( Date . now ( ) / 1000 ) ;
42+
43+ let clientInfo : OAuthClientInformationFull = {
44+ ...clientMetadata ,
45+ client_id : clientId ,
46+ client_secret : clientSecret ,
47+ client_id_issued_at : clientIdIssuedAt ,
48+ client_secret_expires_at : clientSecretExpirySeconds > 0 ? clientIdIssuedAt + clientSecretExpirySeconds : 0
49+ } ;
50+
51+ clientInfo = await store . registerClient ! ( clientInfo ) ;
52+ return clientInfo ;
4653 }
47- } ) ;
54+
55+ // Actual request handler
56+ return ( req : Request , res : Response ) => bodyParser . json ( ) ( req , res , ( err ) => {
57+ if ( err === undefined ) {
58+ register ( req . body ) . then ( ( result ) => {
59+ if ( "error" in result ) {
60+ res . status ( 400 ) . json ( result ) ;
61+ } else {
62+ res . status ( 201 ) . json ( result ) ;
63+ }
64+ } , ( error ) => {
65+ console . error ( "Uncaught error in client registration handler:" , error ) ;
66+ res . status ( 500 ) . end ( "Internal Server Error" ) ;
67+ } ) ;
68+ }
69+ } ) ;
70+ }
0 commit comments