@@ -117,25 +117,36 @@ class TokenHandler {
117117 const grantType = request . body . grant_type ;
118118 const codeVerifier = request . body . code_verifier ;
119119 const isPkce = pkce . isPKCERequest ( { grantType, codeVerifier } ) ;
120+ const isAssertion = this . isClientAssertionRequest ( request ) ;
120121
121- if ( ! credentials . clientId ) {
122- throw new InvalidRequestError ( 'Missing parameter: `client_id`' ) ;
123- }
122+ // @todo - if multiple authentication schemes exist, throw an error
123+ if ( ! isAssertion ) {
124+ if ( ! credentials . clientId ) {
125+ throw new InvalidRequestError ( 'Missing parameter: `client_id`' ) ;
126+ }
124127
125- if ( this . isClientAuthenticationRequired ( grantType ) && ! credentials . clientSecret && ! isPkce ) {
126- throw new InvalidRequestError ( 'Missing parameter: `client_secret`' ) ;
127- }
128+ if ( this . isClientAuthenticationRequired ( grantType ) && ! credentials . clientSecret && ! isPkce ) {
129+ throw new InvalidRequestError ( 'Missing parameter: `client_secret`' ) ;
130+ }
128131
129- if ( ! isFormat . vschar ( credentials . clientId ) ) {
130- throw new InvalidRequestError ( 'Invalid parameter: `client_id`' ) ;
131- }
132+ if ( ! isFormat . vschar ( credentials . clientId ) ) {
133+ throw new InvalidRequestError ( 'Invalid parameter: `client_id`' ) ;
134+ }
132135
133- if ( credentials . clientSecret && ! isFormat . vschar ( credentials . clientSecret ) ) {
134- throw new InvalidRequestError ( 'Invalid parameter: `client_secret`' ) ;
136+ if ( credentials . clientSecret && ! isFormat . vschar ( credentials . clientSecret ) ) {
137+ throw new InvalidRequestError ( 'Invalid parameter: `client_secret`' ) ;
138+ }
139+ } else {
140+ if ( ! credentials . clientAssertion ) {
141+ throw new InvalidClientError ( 'Missing parameter: `client_assertion`' ) ;
142+ }
143+ if ( ! credentials . clientAssertionType ) {
144+ throw new InvalidClientError ( 'Missing parameter: `client_assertion_type`' ) ;
145+ }
135146 }
136147
137148 try {
138- const client = await this . model . getClient ( credentials . clientId , credentials . clientSecret ) ;
149+ const client = await ( isAssertion ? this . model . getClientFromAssertion ?. ( credentials ) : this . model . getClient ( credentials . clientId , credentials . clientSecret ) ) ;
139150
140151 if ( ! client ) {
141152 throw new InvalidClientError ( 'Invalid client: client is invalid' ) ;
@@ -170,7 +181,10 @@ class TokenHandler {
170181 * The client credentials may be sent using the HTTP Basic authentication scheme or, alternatively,
171182 * the `client_id` and `client_secret` can be embedded in the body.
172183 *
173- * @see https://tools.ietf.org/html/rfc6749#section-2.3.1
184+ * Also support the assertion framework for client authentication.
185+ *
186+ * @see https://datatracker.ietf.org/doc/html/rfc6749#section-2.3.1
187+ * @see https://datatracker.ietf.org/doc/html/rfc7521
174188 */
175189
176190 getClientCredentials ( request ) {
@@ -189,6 +203,10 @@ class TokenHandler {
189203 } ;
190204 }
191205
206+ if ( this . isClientAssertionRequest ( request ) ) {
207+ return { clientId : request . body . client_id , clientAssertion : request . body . client_assertion , clientAssertionType : request . body . client_assertion_type } ;
208+ }
209+
192210 if ( pkce . isPKCERequest ( { grantType, codeVerifier } ) ) {
193211 if ( request . body . client_id ) {
194212 return { clientId : request . body . client_id } ;
@@ -302,6 +320,10 @@ class TokenHandler {
302320 response . status = error . code ;
303321 }
304322
323+ isClientAssertionRequest ( { body } ) {
324+ return body . client_assertion && body . client_assertion_type ;
325+ }
326+
305327 /**
306328 * Given a grant type, check if client authentication is required
307329 */
0 commit comments