@@ -115,25 +115,36 @@ class TokenHandler {
115115 const grantType = request . body . grant_type ;
116116 const codeVerifier = request . body . code_verifier ;
117117 const isPkce = pkce . isPKCERequest ( { grantType, codeVerifier } ) ;
118+ const isAssertion = this . isClientAssertionRequest ( request ) ;
118119
119- if ( ! credentials . clientId ) {
120- throw new InvalidRequestError ( 'Missing parameter: `client_id`' ) ;
121- }
120+ // @todo - if multiple authentication schemes exist, throw an error
121+ if ( ! isAssertion ) {
122+ if ( ! credentials . clientId ) {
123+ throw new InvalidRequestError ( 'Missing parameter: `client_id`' ) ;
124+ }
122125
123- if ( this . isClientAuthenticationRequired ( grantType ) && ! credentials . clientSecret && ! isPkce ) {
124- throw new InvalidRequestError ( 'Missing parameter: `client_secret`' ) ;
125- }
126+ if ( this . isClientAuthenticationRequired ( grantType ) && ! credentials . clientSecret && ! isPkce ) {
127+ throw new InvalidRequestError ( 'Missing parameter: `client_secret`' ) ;
128+ }
126129
127- if ( ! isFormat . vschar ( credentials . clientId ) ) {
128- throw new InvalidRequestError ( 'Invalid parameter: `client_id`' ) ;
129- }
130+ if ( ! isFormat . vschar ( credentials . clientId ) ) {
131+ throw new InvalidRequestError ( 'Invalid parameter: `client_id`' ) ;
132+ }
130133
131- if ( credentials . clientSecret && ! isFormat . vschar ( credentials . clientSecret ) ) {
132- throw new InvalidRequestError ( 'Invalid parameter: `client_secret`' ) ;
134+ if ( credentials . clientSecret && ! isFormat . vschar ( credentials . clientSecret ) ) {
135+ throw new InvalidRequestError ( 'Invalid parameter: `client_secret`' ) ;
136+ }
137+ } else {
138+ if ( ! credentials . clientAssertion ) {
139+ throw new InvalidClientError ( 'Missing parameter: `client_assertion`' ) ;
140+ }
141+ if ( ! credentials . clientAssertionType ) {
142+ throw new InvalidClientError ( 'Missing parameter: `client_assertion_type`' ) ;
143+ }
133144 }
134145
135146 try {
136- const client = await this . model . getClient ( credentials . clientId , credentials . clientSecret ) ;
147+ const client = await ( isAssertion ? this . model . getClientFromAssertion ?. ( credentials ) : this . model . getClient ( credentials . clientId , credentials . clientSecret ) ) ;
137148
138149 if ( ! client ) {
139150 throw new InvalidClientError ( 'Invalid client: client is invalid' ) ;
@@ -168,7 +179,10 @@ class TokenHandler {
168179 * The client credentials may be sent using the HTTP Basic authentication scheme or, alternatively,
169180 * the `client_id` and `client_secret` can be embedded in the body.
170181 *
171- * @see https://tools.ietf.org/html/rfc6749#section-2.3.1
182+ * Also support the assertion framework for client authentication.
183+ *
184+ * @see https://datatracker.ietf.org/doc/html/rfc6749#section-2.3.1
185+ * @see https://datatracker.ietf.org/doc/html/rfc7521
172186 */
173187
174188 getClientCredentials ( request ) {
@@ -184,6 +198,10 @@ class TokenHandler {
184198 return { clientId : request . body . client_id , clientSecret : request . body . client_secret } ;
185199 }
186200
201+ if ( this . isClientAssertionRequest ( request ) ) {
202+ return { clientId : request . body . client_id , clientAssertion : request . body . client_assertion , clientAssertionType : request . body . client_assertion_type } ;
203+ }
204+
187205 if ( pkce . isPKCERequest ( { grantType, codeVerifier } ) ) {
188206 if ( request . body . client_id ) {
189207 return { clientId : request . body . client_id } ;
@@ -291,6 +309,10 @@ class TokenHandler {
291309 response . status = error . code ;
292310 }
293311
312+ isClientAssertionRequest ( { body } ) {
313+ return body . client_assertion && body . client_assertion_type ;
314+ }
315+
294316 /**
295317 * Given a grant type, check if client authentication is required
296318 */
0 commit comments