Skip to content

Authorization Code Flow with Proof Key for Code Exchange (PKCE) does not support refresh token #292

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

Closed
hofsa opened this issue May 12, 2021 · 8 comments
Assignees
Labels
status: duplicate A duplicate of another issue

Comments

@hofsa
Copy link

hofsa commented May 12, 2021

Describe the bug
The Authorization Code Flow with Proof Key for Code Exchange (PKCE) allows an Angular-Client to successfully receive an ID-Token, an Access-Token and a Refresh-Token.

But when the client uses the Refresh-Token, he receives a http-StatusCode '401'.

Looks like the problem is in

org.springframework.security.oauth2.server.authorization.authentication.OAuth2ClientAuthenticationProvider

, which has a special-case for the initial PKCE-request (authenticatePkceIfAvailable()) to handle requests without client_secret, but nothing to handle the Refresh-Token-Case after the initial PKCE-Request.

To Reproduce
Execute the Authorization Code Flow with Proof Key for Code Exchange (PKCE) like described under "Samples" and try to use the Refresh-Token.

Expected behavior
The call to "http://127.0.0.1:9000/oauth2/token" with request-parameters

grant_type=refresh_token&
scope=openid%20profile&
refresh_token=y8iG0X4Pppr2mR_41A04kZXgw0zP4VIQp80wUClfK9Ruviv8FJOgP9JJZyOIt4gMtGsDZrJ6jZR1alNCUToGGNTUpXxOk4QxuHrpGhpwdz3v1t4teJDRyibzxZQMZ59f
&client_id=MyOAuthClient

shall return ID-Token, Access-Token and Refresh-Token like the first request with "code" and "code_verifier"

Sample

First request:

http://127.0.0.1:9000/oauth2/authorize?response_type=code&client_id=MyOAuthClient&state=NlJzRzVLa3Y0SXJTYXFtd2J5SEVJU0dTXzA4Z1c1dEI3c3FVVHRWWWpGMTA4&redirect_uri=http%3A%2F%2Feap0012%3A4200&scope=openid%20profile&code_challenge=Kra8cXFsCG8i50pK5ssHge1pdVPwYjiEfIDHtwZEWfM&code_challenge_method=S256&nonce=NlJzRzVLa3Y0SXJTYXFtd2J5SEVJU0dTXzA4Z1c1dEI3c3FVVHRWWWpGMTA4

Redirects to:

http://eap0012:4200/?code=oOjlpPr-kDYhl0UfpQrK_F_PqiGQKW_HfHxZJnP-BDNOhQIZMckr82yLfe_15zSwyVn0z7KqmbQ2iN0qclCXWeS-FMiUdc3HiW7ghF9HZF88CjKr4p0GaImutJfgMpXV&state=NlJzRzVLa3Y0SXJTYXFtd2J5SEVJU0dTXzA4Z1c1dEI3c3FVVHRWWWpGMTA4

Request for Tokens:

http://127.0.0.1:9000/oauth2/token

---Request-Payload
grant_type=authorization_code&code=oOjlpPr-kDYhl0UfpQrK_F_PqiGQKW_HfHxZJnP-BDNOhQIZMckr82yLfe_15zSwyVn0z7KqmbQ2iN0qclCXWeS-FMiUdc3HiW7ghF9HZF88CjKr4p0GaImutJfgMpXV&redirect_uri=http://eap0012:4200&code_verifier=fkVyZzhsNXlaMUVGUS5VVVdkLXZqYmMzMUlQN2tMRzBsUkROQ2dxX1BGV0da&client_id=MyOAuthClient

Returns the Tokens:

----Response-Body
{"access_token":"eyJraWQiOiJmMjlmMmEwMS1jZjc4LTRkYzMtYTc5Ni1mOWYxMTk5M2QzZWEiLCJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJhZG1pbiIsImF1ZCI6Ik15T0F1dGhDbGllbnQiLCJuYmYiOjE2MjA4MjU4MDcsInNjb3BlIjpbIm9wZW5pZCIsInByb2ZpbGUiXSwiaXNzIjoiaHR0cDpcL1wvMTI3LjAuMC4xOjkwMDAiLCJleHAiOjE2MjA4MjYxMDcsImlhdCI6MTYyMDgyNTgwNywianRpIjoiYjU3NGUyNmItYjcyZS00ZjU1LWIyNDYtOTEwYjI4MzMwOTI3In0.RoMSzQlUwnXLytVdstE0uh9z4cdmeP5mqLNB33Mds9qeTHuSackbCS3jq13UFAYGeSDNLo7WxGlRgV3OpDE0oU6YWpdjkqMqw2_1S1C3NdxWXUtw9Q-BiOzAz6eEdFr_QR0sL01MD43Unmo7BzhLwkVB-0-hdo9gBNefAYP3HENBlE_8KJ0Qgbk5b9N2ALryT_M-RMTBWWysmZXKglIDxGSg_ai_RBhWJM-9rwTW21HiuKNzzUjrKggDhnY0axaCvyQxqmcFDwFBoR6xjQvCwIwLxzc1KkKPiAYgsbLMLfy_YxF0rzKVGEU8DNAmrv_Y4h_Q_-AbKHQt2rFnQjhBXQ",
"refresh_token":"y8iG0X4Pppr2mR_41A04kZXgw0zP4VIQp80wUClfK9Ruviv8FJOgP9JJZyOIt4gMtGsDZrJ6jZR1alNCUToGGNTUpXxOk4QxuHrpGhpwdz3v1t4teJDRyibzxZQMZ59f",
"scope":"openid profile",
"id_token":"eyJraWQiOiJmMjlmMmEwMS1jZjc4LTRkYzMtYTc5Ni1mOWYxMTk5M2QzZWEiLCJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJhZG1pbiIsImF1ZCI6Ik15T0F1dGhDbGllbnQiLCJhenAiOiJNeU9BdXRoQ2xpZW50IiwiaXNzIjoiaHR0cDpcL1wvMTI3LjAuMC4xOjkwMDAiLCJleHAiOjE2MjA4Mjc2MDcsImlhdCI6MTYyMDgyNTgwNywibm9uY2UiOiJObEp6UnpWTGEzWTBTWEpUWVhGdGQySjVTRVZKVTBkVFh6QTRaMWMxZEVJM2MzRlZWSFJXV1dwR01UQTQiLCJqdGkiOiJkOTcwZTc3MS00ZWM0LTRiMmUtODcxYi1iYjFlM2Y5M2E4ZWQifQ.NhSxnh-yerJ61IKB0Oj25M32zMZ97-vh8v2dLi8--Jiy39-6vOzxkGWAVk2_ft9rAJAe-xw5HVqIKDKVwslYkQrzc8fGCJlTi4umoALPGAwAaSR8UzkRo-Edf5DxbeJrZ_Cn0QQy6c6M6ajMRZpepbPKSV67oSRRoLW2jcCG8a1QFyp4WNs-YFOaRC_ms2xgJnp-T70KJJpalNTCJTs1eNLvxsWbEQZl0kSfEYtsjAIPQzT-vbINmQm6-JQvDRCVPOcTwe84bwKbzpP55-uyeHC8IFah6fILuxKAA5E16UpXIbQb5E_GUv7QIxE61gS-lxZNbuxOL6M3stETRfPRXQ",
"token_type":"Bearer",
"expires_in":"299"}

Using the Refresh-Token:

http://127.0.0.1:9000/oauth2/token

---Request-Payload
grant_type=refresh_token&scope=openid%20profile&refresh_token=y8iG0X4Pppr2mR_41A04kZXgw0zP4VIQp80wUClfK9Ruviv8FJOgP9JJZyOIt4gMtGsDZrJ6jZR1alNCUToGGNTUpXxOk4QxuHrpGhpwdz3v1t4teJDRyibzxZQMZ59f&client_id=MyOAuthClient

Returns '401', because Client could not be authenticated.

@hofsa hofsa added the type: bug A general bug label May 12, 2021
@wsaca
Copy link

wsaca commented May 12, 2021

Refresh tokens are only supported with confidential clients (with client_secret), its not secure to use refresh tokens with public clients but its possible following this recommendations:

I also would like to see this options implemented, but now I'm authenticating again in bakground before the token expires.

@foogabrielbar316
Copy link

Refresh tokens are only supported with confidential clients (with client_secret), its not secure to use refresh tokens with public clients but its possible following this recommendations:

* https://datatracker.ietf.org/doc/html/draft-ietf-oauth-browser-based-apps-07#section-8

I also would like to see this options implemented, but now I'm authenticating again in bakground before the token expires.

Public clients must also have access to refresh_token.

Consider the following scenario: The user downloads your application from the app store, and every hour he has to go through the flow again (because of the short lifetime of the access_token).

Certainly, because of the bad experience, the application will receive a bad rating.

@bschoenmaeckers
Copy link

bschoenmaeckers commented May 16, 2021

Native apps do not have the same recommendations as browser-based apps. So native apps should support refresh tokens with extending lifetime, even public clients without secret.

https://datatracker.ietf.org/doc/html/rfc8252

@jgrandja
Copy link
Collaborator

@hofsa Thank you for reporting this as you uncovered a bug. I'm going to close this in favour of gh-296.

Also, see gh-297 as refresh_token capability for public clients will be implemented at a later point.

@jgrandja jgrandja self-assigned this May 20, 2021
@jgrandja jgrandja added status: duplicate A duplicate of another issue and removed type: bug A general bug labels May 20, 2021
@bf39l
Copy link

bf39l commented Jul 2, 2021

I got a question about this rule (maybe not appropriate asking this question in here)

MUST NOT extend the lifetime of the new refresh token beyond the lifetime of the initial refresh token

written in Oauth-browser-based-apps section 8
in their example: (init) 1hr access_token + 24hr refresh_token => (later) 1hr access_token + 23hr refresh_token

What's the difference between "given browser based apps a 24hr refresh_token + 1hr access_token" and "given 24hr access_token but no refresh_token"?
As far as I understand with short access_token and long refresh_token can prevent "person" who can only intercept access_token

@eiswind
Copy link

eiswind commented Aug 5, 2021

@hofsa May I ask you to point me to an example with an Angular Client?
I try https://github.com/manfredsteyer/angular-oauth2-oidc/ but I desperatley fail at doing so.

@hofsa
Copy link
Author

hofsa commented Aug 16, 2021

@eiswind I used the "angular-oauth2-oidc" - library from the link you mentioned. I followed the steps on the project-page and was able to get the client up-and-running without any problems. Maybe you should use another authorization-server first. I used the one from OKTA.

@vishalzanzrukia
Copy link

vishalzanzrukia commented Nov 18, 2022

I agree with security concerns but If someone wants to support refresh_token with public clients too, here is a full demo with customizations. (@hofsa this may help you)
https://github.com/vishalzanzrukia/spring-security5-oauth2-client-server
Any feedbacks are welcome

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
status: duplicate A duplicate of another issue
Projects
None yet
Development

No branches or pull requests

8 participants