Skip to content
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

refresh request discards id_token #364

Closed
muir opened this issue Apr 11, 2023 · 4 comments · Fixed by #423
Closed

refresh request discards id_token #364

muir opened this issue Apr 11, 2023 · 4 comments · Fixed by #423
Labels
client pkg/client/* issues enhancement New feature or request released on @next released
Milestone

Comments

@muir
Copy link
Contributor

muir commented Apr 11, 2023

Is your feature request related to a problem? Please describe.

Token refresh MAY return an id_token. See oipenid.net

rp.RefreshAccessToken discards the returned id_token (assuming it was returned).

Debugging shows an id_token returned in the response, but the returned model, oath2.Token doesn't include IDToken.

Why do I care? Keycloak wants id_token_hint filled out when doing a logout.

Describe the solution you'd like

Introduce rp.RefreshTokens and deprecate rp.RefreshAccessToken. The new function would return

type Tokens struct {
   oauth2.Token
   IDToken string
}

Describe alternatives you've considered

Consiering:

  • return *oidc.Tokens[C] instead of the above simple composite.
    @muhlemmer : what do you think?

  • build RefreshTokens() on top of oauth2.ReuseTokenSourceWithExpiry()
    That has to be fed an *oauth2.Token so the current API to RefreshAccessToken probably has to change unless we can build an *oauth2.Token from what we have there. Maybe? I may give this a try because it it works, the resulting *oauth2.Token could include an id_token that can be extracted with Extra().

    This might look like:

func RefreshTokens(ctx context.Context, rp RelyingParty, currentToken *oauth2.Token, earlyExpire time.Duration) (*oauth2.Token, error) {
        tokenSource := rp.OAuthConfig().TokenSource(ctx, currentToken)
        if earlyExpire != 0 {
                tokenSource = oauth2.ReuseTokenSourceWithExpiry(currentToken, tokenSource, earlyExpire)
        }
        return tokenSource.Token()
}
  • Keep the current API and embed the id_token using token.WithExtra().

Rejected:

  • a separate function to refresh the id_token
  • not deprecating RefreshAccessToken
    let's not keep supporting a broken interface.
  • changing RefreshAccessToken only in v3

Additional context

The server side, in pkg/op, returns an id_token for token refresh but pkg/client/rp ignores it.

@muhlemmer
Copy link
Collaborator

Merged the feat into main. Decided to keep the issue open, so we can make the breaking change to v3 /next.

Introduce rp.RefreshTokens and deprecate rp.RefreshAccessToken. The new function would return

type Tokens struct {
  oauth2.Token
  IDToken string
}

This sounds like a good and simple solution.

return *oidc.Tokens[C] instead of the above simple composite.
@muhlemmer : what do you think?

Is also an option, however the IDTokenClaims C field are the decoded, verified and unmarshalled claims. This means that rp.RefreshAccessToken() needs to get additional functionality that takes care of that, like we do in rp.CodeExchange().

Both option sound good to me, but depends how much work we want to put into this :).

@muhlemmer muhlemmer added this to the v3 milestone Apr 22, 2023
@muhlemmer muhlemmer added the client pkg/client/* issues label Apr 22, 2023
@muir
Copy link
Contributor Author

muir commented Apr 24, 2023

@muhlemmer do you want to introduce rp.RefreshTokens now? That's not a breaking change.

muhlemmer added a commit that referenced this issue Aug 16, 2023
BREAKING CHANGE:
- rename RefreshAccessToken to RefreshToken
- RefreshToken returns *oidc.Tokens instead of *oauth2.Token

This change allows the return of the id_token in an explicit manner,
as part of the oidc.Tokens struct.
The return type is now consistent with the CodeExchange function.

When an id_token is returned, it is verified.
In case no id_token was received,
RefreshTokens will not return an error.

As per specifictation:
https://openid.net/specs/openid-connect-core-1_0.html#RefreshTokenResponse

Upon successful validation of the Refresh Token,
the response body is the Token Response of Section 3.1.3.3
except that it might not contain an id_token.

Closes #364
@muhlemmer muhlemmer linked a pull request Aug 16, 2023 that will close this issue
muhlemmer added a commit that referenced this issue Aug 18, 2023
BREAKING CHANGE:
- rename RefreshAccessToken to RefreshToken
- RefreshToken returns *oidc.Tokens instead of *oauth2.Token

This change allows the return of the id_token in an explicit manner,
as part of the oidc.Tokens struct.
The return type is now consistent with the CodeExchange function.

When an id_token is returned, it is verified.
In case no id_token was received,
RefreshTokens will not return an error.

As per specifictation:
https://openid.net/specs/openid-connect-core-1_0.html#RefreshTokenResponse

Upon successful validation of the Refresh Token,
the response body is the Token Response of Section 3.1.3.3
except that it might not contain an id_token.

Closes #364
@github-actions
Copy link

🎉 This issue has been resolved in version 3.0.0-next.9 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

@github-actions
Copy link

🎉 This issue has been resolved in version 3.0.0 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
client pkg/client/* issues enhancement New feature or request released on @next released
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants