feat: rp.RefreshAccessToken() now may provide an updated IDToken (#365)

This commit is contained in:
David Sharnoff 2023-04-13 06:37:50 -07:00 committed by GitHub
parent 8730a1685e
commit f0d46593e0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 14 additions and 4 deletions

View file

@ -61,12 +61,18 @@ func callTokenEndpoint(request interface{}, authFn interface{}, caller TokenEndp
if err := httphelper.HttpRequest(caller.HttpClient(), req, &tokenRes); err != nil { if err := httphelper.HttpRequest(caller.HttpClient(), req, &tokenRes); err != nil {
return nil, err return nil, err
} }
return &oauth2.Token{ token := &oauth2.Token{
AccessToken: tokenRes.AccessToken, AccessToken: tokenRes.AccessToken,
TokenType: tokenRes.TokenType, TokenType: tokenRes.TokenType,
RefreshToken: tokenRes.RefreshToken, RefreshToken: tokenRes.RefreshToken,
Expiry: time.Now().UTC().Add(time.Duration(tokenRes.ExpiresIn) * time.Second), Expiry: time.Now().UTC().Add(time.Duration(tokenRes.ExpiresIn) * time.Second),
}, nil }
if tokenRes.IDToken != "" {
token = token.WithExtra(map[string]any{
"id_token": tokenRes.IDToken,
})
}
return token, nil
} }
type EndSessionCaller interface { type EndSessionCaller interface {

View file

@ -53,6 +53,7 @@ func TestRelyingPartySession(t *testing.T) {
t.Logf("new token type %s", newTokens.TokenType) t.Logf("new token type %s", newTokens.TokenType)
t.Logf("new expiry %s", newTokens.Expiry.Format(time.RFC3339)) t.Logf("new expiry %s", newTokens.Expiry.Format(time.RFC3339))
require.NotEmpty(t, newTokens.AccessToken, "new accessToken") require.NotEmpty(t, newTokens.AccessToken, "new accessToken")
assert.NotEmpty(t, newTokens.Extra("id_token"), "new idToken")
t.Log("------ end session (logout) ------") t.Log("------ end session (logout) ------")
@ -141,7 +142,6 @@ func TestResourceServerTokenExchange(t *testing.T) {
require.Error(t, err, "refresh token") require.Error(t, err, "refresh token")
assert.Contains(t, err.Error(), "subject_token is invalid") assert.Contains(t, err.Error(), "subject_token is invalid")
require.Nil(t, tokenExchangeResponse, "token exchange response") require.Nil(t, tokenExchangeResponse, "token exchange response")
} }
func RunAuthorizationCodeFlow(t *testing.T, opServer *httptest.Server, clientID, clientSecret string) (provider rp.RelyingParty, accessToken, refreshToken, idToken string) { func RunAuthorizationCodeFlow(t *testing.T, opServer *httptest.Server, clientID, clientSecret string) (provider rp.RelyingParty, accessToken, refreshToken, idToken string) {

View file

@ -13,7 +13,7 @@ import (
// jwtProfileTokenSource implement the oauth2.TokenSource // jwtProfileTokenSource implement the oauth2.TokenSource
// it will request a token using the OAuth2 JWT Profile Grant // it will request a token using the OAuth2 JWT Profile Grant
// therefore sending an `assertion` by singing a JWT with the provided private key // therefore sending an `assertion` by signing a JWT with the provided private key
type jwtProfileTokenSource struct { type jwtProfileTokenSource struct {
clientID string clientID string
audience []string audience []string

View file

@ -620,6 +620,10 @@ type RefreshTokenRequest struct {
GrantType oidc.GrantType `schema:"grant_type"` GrantType oidc.GrantType `schema:"grant_type"`
} }
// RefreshAccessToken performs a token refresh. If it doesn't error, it will always
// provide a new AccessToken. It may provide a new RefreshToken, and if it does, then
// the old one should be considered invalid. It may also provide a new IDToken. The
// new IDToken can be retrieved with token.Extra("id_token").
func RefreshAccessToken(rp RelyingParty, refreshToken, clientAssertion, clientAssertionType string) (*oauth2.Token, error) { func RefreshAccessToken(rp RelyingParty, refreshToken, clientAssertion, clientAssertionType string) (*oauth2.Token, error) {
request := RefreshTokenRequest{ request := RefreshTokenRequest{
RefreshToken: refreshToken, RefreshToken: refreshToken,