@@ -114,25 +114,36 @@ class TokenHandler {
114114 const grantType = request . body . grant_type ;
115115 const codeVerifier = request . body . code_verifier ;
116116 const isPkce = pkce . isPKCERequest ( { grantType, codeVerifier } ) ;
117+ const isAssertion = this . isClientAssertionRequest ( request ) ;
117118
118- if ( ! credentials . clientId ) {
119- throw new InvalidRequestError ( 'Missing parameter: `client_id`' ) ;
120- }
119+ // @todo - if multiple authentication schemes exist, throw an error
120+ if ( ! isAssertion ) {
121+ if ( ! credentials . clientId ) {
122+ throw new InvalidRequestError ( 'Missing parameter: `client_id`' ) ;
123+ }
121124
122- if ( this . isClientAuthenticationRequired ( grantType ) && ! credentials . clientSecret && ! isPkce ) {
123- throw new InvalidRequestError ( 'Missing parameter: `client_secret`' ) ;
124- }
125+ if ( this . isClientAuthenticationRequired ( grantType ) && ! credentials . clientSecret && ! isPkce ) {
126+ throw new InvalidRequestError ( 'Missing parameter: `client_secret`' ) ;
127+ }
125128
126- if ( ! isFormat . vschar ( credentials . clientId ) ) {
127- throw new InvalidRequestError ( 'Invalid parameter: `client_id`' ) ;
128- }
129+ if ( ! isFormat . vschar ( credentials . clientId ) ) {
130+ throw new InvalidRequestError ( 'Invalid parameter: `client_id`' ) ;
131+ }
129132
130- if ( credentials . clientSecret && ! isFormat . vschar ( credentials . clientSecret ) ) {
131- throw new InvalidRequestError ( 'Invalid parameter: `client_secret`' ) ;
133+ if ( credentials . clientSecret && ! isFormat . vschar ( credentials . clientSecret ) ) {
134+ throw new InvalidRequestError ( 'Invalid parameter: `client_secret`' ) ;
135+ }
136+ } else {
137+ if ( ! credentials . clientAssertion ) {
138+ throw new InvalidClientError ( 'Missing parameter: `client_assertion`' ) ;
139+ }
140+ if ( ! credentials . clientAssertionType ) {
141+ throw new InvalidClientError ( 'Missing parameter: `client_assertion_type`' ) ;
142+ }
132143 }
133144
134145 try {
135- const client = await this . model . getClient ( credentials . clientId , credentials . clientSecret ) ;
146+ const client = await ( isAssertion ? this . model . getClientFromAssertion ?. ( credentials ) : this . model . getClient ( credentials . clientId , credentials . clientSecret ) ) ;
136147
137148 if ( ! client ) {
138149 throw new InvalidClientError ( 'Invalid client: client is invalid' ) ;
@@ -167,7 +178,10 @@ class TokenHandler {
167178 * The client credentials may be sent using the HTTP Basic authentication scheme or, alternatively,
168179 * the `client_id` and `client_secret` can be embedded in the body.
169180 *
170- * @see https://tools.ietf.org/html/rfc6749#section-2.3.1
181+ * Also support the assertion framework for client authentication.
182+ *
183+ * @see https://datatracker.ietf.org/doc/html/rfc6749#section-2.3.1
184+ * @see https://datatracker.ietf.org/doc/html/rfc7521
171185 */
172186
173187 getClientCredentials ( request ) {
@@ -183,6 +197,10 @@ class TokenHandler {
183197 return { clientId : request . body . client_id , clientSecret : request . body . client_secret } ;
184198 }
185199
200+ if ( this . isClientAssertionRequest ( request ) ) {
201+ return { clientId : request . body . client_id , clientAssertion : request . body . client_assertion , clientAssertionType : request . body . client_assertion_type } ;
202+ }
203+
186204 if ( pkce . isPKCERequest ( { grantType, codeVerifier } ) ) {
187205 if ( request . body . client_id ) {
188206 return { clientId : request . body . client_id } ;
@@ -289,6 +307,10 @@ class TokenHandler {
289307 response . status = error . code ;
290308 }
291309
310+ isClientAssertionRequest ( { body } ) {
311+ return body . client_assertion && body . client_assertion_type ;
312+ }
313+
292314 /**
293315 * Given a grant type, check if client authentication is required
294316 */
0 commit comments