-
-
Notifications
You must be signed in to change notification settings - Fork 47
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
PKCE Refresh token #288
Comments
Hello @kuselan84 thank you for getting in contact. What is exactly the nature of your issue?
|
Hi @jankapunkt, I'm trying implement PKCE flow using guide at PKCE Support. I send auth request as follows:
I received code to redirect uri successfully. Then I request token as follows:
I received access token successfully. Then I request access token again using refresh token as follows:
It failed with this error message:
The request works if I send client_secret parameter. However it ignore code_verifier verification. |
Perhaps it could be fixed so that neither the code_verifier nor the client_secret are required.
|
@kuselan84 I read up again the RFC and some resources and there is indeed no specification on the RFC about the refresh token in combination with PKCE. I also think this is why we did not 100% cover this in our implementation so far. This is very unexpected. Assumptions
Concerns
I agree with this. However I'm still unsure how Is this even possible in a PKCE scenario? From how I see it, the client is considered unsafe. A stack answer is also inconclusive on this. SummaryI'm generally positive with you as the RFC and literature is inconclusive and if in doubt we should always decide for the flexibility and let developers decide. However we will have to warn over the concerns in the documentation. I would still not consider this as a bug, though. |
Thank you for the reply, @jankapunkt. I have opted to disable client_secret on token endpoint like this as per documentation:
I'm going to implement Refresh token reuse Detection to protect refresh token. |
If there is no veto from @jorenvandeweyer @dhensby @shrihari-prakash I'm going to implement this. The impl. also needs to update the tests accordingly. |
disclaimer: I have not familiarised myself with the PKCE spec recently My understanding PKCE is primarily aimed at clients that are deemed to be unable to securely store sensitive date (hence, there is no |
Hello @jankapunkt , In my opinion, I think it is normal that the But in case of refresh tokens, there is none of the redirect stuff and it is purely handled within the application. I don't see why a |
@dhensby @shrihari-prakash thanks for your input. The biggest problem of all this is, that the standard says NOTHING about all this. Real edge-case here. |
So there are two issues at play here.
Should PKCE flows return refresh tokens?This is actually less a question about PKCE and more about public vs confidential clients. tl;dr: Public clients can't store secrets, confidential clients can. PKCE code challenges can (and are) used by confidential clients as it's recommended in some of the more advanced standards such as FAPI 2.0. The OAuth specification essentially says, it's up to the risk tolerance of the authorisation server as to whether refresh tokens are issued:
Personally, I would not issue refresh tokens to any public clients, but of course native apps that have access to store refresh tokens in secure enclaves, certainly feels like an acceptable level of risk following a PKCE flow. I'd note that in section 1.1 of the PKCE extension there is no mention of refresh tokens forming part of the protocol, whereas the OAuth protocol does mention them in the equivalent section section 1.5 of its spec. Certainly not conclusive, but a fairly clear omission. My view on this is: PKCE flows issuing refresh tokens is up to the server, the server should be storing meta data about the client (ie: whether it is a public or confidential client) and acting on that information as it feels appropriate. NB: If the client has authentication credentials (ie: it has a Answer: Yes, PKCE can (but probably shouldn't for public clients) release refresh tokens. How is a refresh token obtained through PKCE exchanged?The specification is annoyingly vague around this. If we start at refreshing an access token it says:
[Section 3.2.1] says:
Section 2.3 says:
So all the authentication rhetoric is around confidential clients... However it does also sneak in these statements that could apply to PKCE flows:
and
Is the PKCE flow establishing an authentication method with the client, or just a single-use challenge? I think as with the question of issuing refresh tokens at all, this really comes down to the level of acceptable risk for the authorisation server. On the one hand, I agree with @shrihari-prakash - the On the other hand, associating the challenge with the client and for subsequent refreshes does seem sensible if one is going to actually issue refresh tokens and they want some level of assurance that they are refreshing the token with the same client as before. It fits in with the implied spec that the request should include the same authentication that was used in the original token exchange. Although this is a rather long and meandering post, I think I'm settling that the challenge does not need to be supplied when exchanging the refresh token when using a public client. It is completely academic for a public client to provide the code challenge with a refresh token, if the client is not capable of secure storage, then a refresh token should not be issued. If it is capable of secure storage of the refresh token, then it doesn't need the code challenge to prove itself. A public client without the capability of secure storage wouldn't be able to store the challenge any more securely than the refresh token, so if one can be extracted from the client, then so can the other - providing both provides no real security benefit over just the refresh token. Lastly, it appears that that Okta (who run Auth0) don't require the challenge when exchanging refresh tokens. Just to touch on this specific issue as raised by OP: If the client has a
@jankapunkt is quite right in his "assumption", that if the client has a client secret, that it must provide that during the refresh exchange. In regards to resolving this issue, I think we need to add the concept of confidential/public clients to the library because it's not just a case of enable or disable authentication on refresh endpoints, it's a case of appropriately authenticating a client holistically with the entire request context. |
To summarise two mechanism are here confused as one.
They should both be implemented independently.
PKCE extension
When the PKCE extension is used in an authentication flow, the server must require the code verifier on the code exchange. The code verifier should never be used outside this flow (so not in the refresh token flow). ExamplesConfidential Client without PKCEgrant_type=authorization_code&
client_id=myclient&
client_secret=mysecret&
code=8b51da4fade34a5ccf0d1dc40816812052e2b3ae Confidential Client with PKCE
Public Client without PKCE
Public Client with PKCE
Confidential & Public ClientThis is currently not implemented in the library but can be implemented by the implementor. We already have an open issue for this improvement. #81 @jankapunkt Which changes are you proposing? |
@jorenvandeweyer's summary is correct here. With With |
@jorenvandeweyer @dhensby @shrihari-prakash how do we proceed with this? I think we should make a decision very soon. I currently have a milestone crunch until mid-November. After that I'll be free- @MartinKolarik offered to provide a PR but I may not be available to review and test until mid-Nov. What about you? |
On my side, I am more inclined towards the current behavior of the library because verifying refresh of a token is not a job of the code and verifier because there is no redirection / app handler registration involved in this step, but as @dhensby mentioned, this can definitely enhance the level of reassurance a bit. Is it a wiser choice to accept an option to opt into this new behavior? |
Token handler on PCKE flow is not verifying code_verifier and expecting client_secret.
Providing client_secret will defeat PKCE flow.
Please assist.
The text was updated successfully, but these errors were encountered: