nextauthjs / next-auth

Authentication for the Web.
https://authjs.dev
ISC License
24.19k stars 3.36k forks source link

Provide JWKS Endpoint and generated RS256 keys #3150

Closed micheljung closed 2 years ago

micheljung commented 2 years ago

Description 📓

Since #1543 was closed for not following the template, here's my attempt

NextAuth.js can generate JWKs but currently does so with a symmetric HS512 key. In order for another application (e.g. API backend) to verify a JWT, it needs to know the signing key. Therefore, generated keys are basically useless and the key needs to be generated by hand and configured in both applications.

To avoid having to generate and copy the signing key, a private/public key pair could be generated by NextAuth.js instead, and the public key would be exposed by [...nextauth].js as jwks. See https://eu.battle.net/oauth/jwks/certs as an example of a JWKS endpoint and Auth0's Navigating RS256 and JWKS about how it works.

This way, consumers can look up the public key and verify the JWT without having the signing key configured.

How to reproduce ☕️

A non-existing feature can't be reproduced.

Contributing 🙌🏽

No, I am afraid I cannot help regarding this

balazsorban44 commented 2 years ago

next-auth does not try to be an Identity Provider, so I feel this would not match our goals with the library well, at least not in the short term...

Your external APIs should generally use the access_token provided by your Identity Provider (the one that you log in within your app).

If you use API routes at the backend, that will already understand and parse the JWT as expected (eg using getToken).

As an FYI, the JWT creation has been reworked in #3039 and all JWTs are encrypted (JWE) by default in next-auth@4.0.0-beta.5 and upwards, and there is no JWT signing by default either.

I will leave this open to see if there is interest around this, but if it becomes stale/closed again, I am inclined to leave it that way.

micheljung commented 2 years ago

Ok, I was hoping I could reuse the JWT but I'll look into using the access_token again.

micheljung commented 2 years ago

I got it working by passing the access_token via callbacks to session as documented and sending it via Authorization: Bearer $ACCESS_TOKEN header to my API calls which will then call the IDP for introspection. As for me, this can be closed.

balazsorban44 commented 2 years ago

that is more like the intended behavior! 🎉

hems commented 1 year ago

@micheljung wrote:

I got it working by passing the access_token via callbacks to session as documented and sending it via Authorization: Bearer $ACCESS_TOKEN header to my API calls which will then call the IDP for introspection. As for me, this can be closed.


Assuming by "IDP" you mean "Identity Provider", could you explain how you do "call the IDP" for introspection?

Considering there are multiple credential providers ( credentials, email, google, facebook, etcs... ) It sounds counter-intuitive to call the IDP directly on a case by case? I think i understood something wrong from your post?

hems commented 1 year ago

@balazsorban44 wrote:

that is more like the intended behavior! 🎉


If sending the access_token as Bearer is the intended behaviour wouldn't it make sense to have documentation for such function for instance on the website's GUIDES > BASICS or on github?

I understand this is a fairly common requirement ( to be able to share the token and validate it on a different app ) but unfortunately I could not find documentaiton on how to do it on the website or on the github repo.. Did i miss it somewhere?

hems commented 1 year ago

What do you mean by "encrypted by default" but "there is no JWT signing by default" @balazsorban44 ?

From my understanding when we say "encrypted" it means it was "signed" by a private key so i don't really understand what you mean by "it's encrypted by default but no JWT signing by default"?

As an FYI, the JWT creation has been reworked in #3039 and all JWTs are encrypted (JWE) by default in next-auth@4.0.0-beta.5 and upwards, and there is no JWT signing by default either.

hems commented 1 year ago

After some reading and extra considerations i came to this implementation described here

Please let me know your thoughts @micheljung / @balazsorban44 !

thanks a lot for sharing your thoughts / work on the library.

CharlesHolbrow commented 4 months ago

I got it working by passing the access_token via callbacks to session as documented and sending it via Authorization: Bearer $ACCESS_TOKEN header to my API calls which will then call the IDP for introspection. As for me, this can be closed.

@micheljung Any chance you could help me understand this?

If I understand correctly, when the user logs in to your app with a Provider (such as GitHub, Google, etc) they receive an access token FROM that provider. Then somehow, you set the Authorization: Bearer $ACCESS_TOKEN header on future calls from the client/browser.

TLDR: HOW do you forward the Provider access token to the Client? I see the GitHub access and refresh bearer tokens in the account parameter passed to the signIn callback on the server, but I don't see how to forward this information to the client/session.

Many, many thanks if you can help me 🙏🙏🙏

EDIT: I found the answer. Forwarding Provider Access tokens can be accomplished with a combination of the jwt and session callbacks, documented here