@@ -114,25 +114,36 @@ class TokenHandler {
114
114
const grantType = request . body . grant_type ;
115
115
const codeVerifier = request . body . code_verifier ;
116
116
const isPkce = pkce . isPKCERequest ( { grantType, codeVerifier } ) ;
117
+ const isAssertion = this . isClientAssertionRequest ( request ) ;
117
118
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
+ }
121
124
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
+ }
125
128
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
+ }
129
132
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
+ }
132
143
}
133
144
134
145
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 ) ) ;
136
147
137
148
if ( ! client ) {
138
149
throw new InvalidClientError ( 'Invalid client: client is invalid' ) ;
@@ -167,7 +178,10 @@ class TokenHandler {
167
178
* The client credentials may be sent using the HTTP Basic authentication scheme or, alternatively,
168
179
* the `client_id` and `client_secret` can be embedded in the body.
169
180
*
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
171
185
*/
172
186
173
187
getClientCredentials ( request ) {
@@ -183,6 +197,10 @@ class TokenHandler {
183
197
return { clientId : request . body . client_id , clientSecret : request . body . client_secret } ;
184
198
}
185
199
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
+
186
204
if ( pkce . isPKCERequest ( { grantType, codeVerifier } ) ) {
187
205
if ( request . body . client_id ) {
188
206
return { clientId : request . body . client_id } ;
@@ -289,6 +307,10 @@ class TokenHandler {
289
307
response . status = error . code ;
290
308
}
291
309
310
+ isClientAssertionRequest ( { body } ) {
311
+ return body . client_assertion && body . client_assertion_type ;
312
+ }
313
+
292
314
/**
293
315
* Given a grant type, check if client authentication is required
294
316
*/
0 commit comments