-
Notifications
You must be signed in to change notification settings - Fork 141
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Jwt client authn #291
Jwt client authn #291
Conversation
Thanks for your work @madaster97 - will take a look through this sometime this week |
Hi @madaster97 - sorry, I haven't forgotten this. It might be a little while before I get round to reviewing it |
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. If you have not received a response for our team (apologies for the delay) and this is still a blocker, please reply with additional information or just a ping. Thank you for your contribution! 🙇♂️ |
Hi @madaster97 - we do have this in the Roadmap to look at at some point over the next few months, so will reopen this when we do |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@madaster97 - left some comments
Going to be working on this in a week or so, so happy to take this branch over if you're busy with something else.
@@ -58,6 +59,23 @@ const auth = function (params) { | |||
debug('logout handling route not applied'); | |||
} | |||
|
|||
// jwks url route, configured with routes.jwksUrl |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the benefit of publishing a jwksUri endpoint?
Also clientAssertionConfig.signingKey
is a private key, so you don't want to make it publicly accessible
@@ -13,9 +13,12 @@ app.use( | |||
response_type: 'code', | |||
}, | |||
clientAuthMethod: 'private_key_jwt', | |||
clientAssertionSigningKey: fs.readFileSync( | |||
clientAssertionConfig: { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't need to specify the alg if we're not publishing a jwks uri
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@adamjmcgrath - There are some cases where you need to explicitly provide an alg. For instance you can use an RSA private key with any of RS 256/384/512, and somewhere along the way openid-client or jose are defaulting to RS256 for an RSA private key.
I can think of two options to let callers specify their alg:
- Keep the current setup, noting that we're passing the alg to openid-client here after parsing with jose's JWK module
- Explicitly require a jwk and inspect the alg (maybe warning if it's missing and that we'll choose a default)
Note that openid-clilent won't throw an error for invalid algs until runtime. For example, if I try to specify ES384 but give an RSA private key I get the following, but not until I actually attempt a grant:
BadRequestError: no key found in client jwks to sign a client assertion with using alg ES384
at C:\Users\adams\source\node\express-openid-connect\middleware\auth.js:138:31
at processTicksAndRejections (node:internal/process/task_queues:96:5)
What do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey @madaster97 - sorry for the delay responding, I was away last week
Your right, we should allow specifying the algorithm, but it should be optional
By default openid-client
uses one of the token_endpoint_auth_signing_alg_values_supported
if you don't specify - so I just need to figure out whether the default should be RS256
or undefined
(let openid-client pick one from token_endpoint_auth_signing_alg_values_supported
)
Also, can we make the config flat,eg clientAssertionSigningKey
and clientAssertionSigningKeyAlg
(like idTokenSigningAlg
)
@@ -17,6 +17,7 @@ const config = { | |||
clients: [ | |||
client, | |||
Object.assign({}, client, { | |||
client_secret: undefined, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This shouldn't be necessary
} | ||
|
||
if (config.clientAuthMethod == 'private_key_jwt') { | ||
const configTokenAuthAlg = config.clientAssertionConfig.signingKey; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This would be signingAlg
- but I would rather avoid requiring the user to specify this if we can
is: true, | ||
then: Joi.string().invalid('none').messages({ | ||
'any.only': | ||
'"clientAuthMethod" cannot be "none" when "response_type" includes "code"', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I want to default clientAuthMethod
from clientAssertionSigningKey
or clientSecret
- so this should be
'either a "clientSecret" or "clientAuthMethod" is required for a "response_type" that includes "code"'
Thanks @adamjmcgrath - Yeah I'm looking into these comments. Right now just trying to get re-setup for testing |
}; | ||
case 'client_secret_basic': | ||
case 'client_secret_post': | ||
return { client_secret: config.clientSecret }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also , I think there's a use case for a client secret even when using private_key_jwt
(when the ID Token signing alg is HS256
) but I will confirm
Thanks for your work on this @madaster97 - I'm going to continue it now on the jwt-client-authn branch |
Thanks @adamjmcgrath - I didn't respond on your other comments but I agree with all but 1. Currently the jwks URL endpoint (which I agree we can take out) is explicitly only showing the public components of the key using
|
Ah yep, gotcha, thanks Apologies for taking ages reviewing then being in a rush to merge, this is just because of how our work is prioritised behind the scenes. I'll add you to the PR when I raise the final one against master in case you want to take a look |
Description
This PR adds JWT based client authentication to the library (building on Adam's initial implementation). All signing algorithms supported by jose@2.0.5 will be supported here (though upgrading jose versions is an option). This PR also adds a configurable JWKS endpoint, so that the public keys associated with the client can be distributed.
References
Following up on my issue for this enhancement.
GitHub Project where I documented the additions
Testing
There's an example JWT client that @adamjmcgrath already added. I've been using that to test, but I've been having issues getting it to work against the fixture provider. I think the
run_example.js
script is accidentally setting up a client_secret client instead of a jwt one. I've been testing against an example Openid Provider that supports private_key_jwt clients and it's worked so far.TBD on testing
Checklist
master