Skip to content

Commit c4fe21c

Browse files
committed
refactor: refresh token rotation interfaces
Previously, the refresh token handler was using a combination of delete/update storage primitives. This made optimizing and implementing the refresh token handling difficult. Going forward, the RefreshTokenStorage must implement `RotateRefreshToken`. Token creation continues to be separated. BREAKING CHANGES: Method `RevokeRefreshTokenMaybeGracePeriod` was removed from `handler/fosite/TokenRevocationStorage`. Interface `handler/fosite/RefreshTokenStorage` has changed: - `CreateRefreshToken` now takes an additional argument `accessSignature` to keep track of refresh/access token pairs: - A new method `RotateRefreshToken` was added, which revokes old refresh tokens and associated access tokens: ```patch // handler/fosite/storage.go type RefreshTokenStorage interface { - CreateRefreshTokenSession(ctx context.Context, signature string, request fosite.Requester) (err error) + CreateRefreshTokenSession(ctx context.Context, signature string, accessSignature string, request fosite.Requester) (err error) GetRefreshTokenSession(ctx context.Context, signature string, session fosite.Session) (request fosite.Requester, err error) DeleteRefreshTokenSession(ctx context.Context, signature string) (err error) + RotateRefreshToken(ctx context.Context, requestID string, refreshTokenSignature string) (err error) } ```
1 parent db74aa7 commit c4fe21c

37 files changed

+127
-316
lines changed

Makefile

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
export PATH := .bin:${PATH}
2+
13
format: .bin/goimports .bin/ory node_modules # formats the source code
24
.bin/ory dev headers copyright --type=open-source
35
.bin/goimports -w .
@@ -18,6 +20,9 @@ test: # runs all tests
1820
.bin/licenses: Makefile
1921
curl https://raw.githubusercontent.com/ory/ci/master/licenses/install | sh
2022

23+
.bin/mockgen:
24+
go build -o .bin/mockgen github.com/golang/mock/mockgen
25+
2126
.bin/ory: Makefile
2227
curl https://raw.githubusercontent.com/ory/meta/master/install.sh | bash -s -- -b .bin ory v0.1.48
2328
touch .bin/ory
@@ -26,4 +31,7 @@ node_modules: package-lock.json
2631
npm ci
2732
touch node_modules
2833

34+
gen: .bin/goimports .bin/mockgen # generates mocks
35+
./generate-mocks.sh
36+
2937
.DEFAULT_GOAL := help

handler/oauth2/flow_authorize_code_token.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ func (c *AuthorizeExplicitGrantHandler) PopulateTokenEndpointResponse(ctx contex
169169
} else if err = c.CoreStorage.CreateAccessTokenSession(ctx, accessSignature, requester.Sanitize([]string{})); err != nil {
170170
return errorsx.WithStack(fosite.ErrServerError.WithWrap(err).WithDebug(err.Error()))
171171
} else if refreshSignature != "" {
172-
if err = c.CoreStorage.CreateRefreshTokenSession(ctx, refreshSignature, requester.Sanitize([]string{})); err != nil {
172+
if err = c.CoreStorage.CreateRefreshTokenSession(ctx, refreshSignature, accessSignature, requester.Sanitize([]string{})); err != nil {
173173
return errorsx.WithStack(fosite.ErrServerError.WithWrap(err).WithDebug(err.Error()))
174174
}
175175
}

handler/oauth2/flow_authorize_code_token_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -498,7 +498,7 @@ func TestAuthorizeCodeTransactional_HandleTokenEndpointRequest(t *testing.T) {
498498
Times(1)
499499
mockCoreStore.
500500
EXPECT().
501-
CreateRefreshTokenSession(propagatedContext, gomock.Any(), gomock.Any()).
501+
CreateRefreshTokenSession(propagatedContext, gomock.Any(), gomock.Any(), gomock.Any()).
502502
Return(nil).
503503
Times(1)
504504
mockTransactional.
@@ -627,7 +627,7 @@ func TestAuthorizeCodeTransactional_HandleTokenEndpointRequest(t *testing.T) {
627627
Times(1)
628628
mockCoreStore.
629629
EXPECT().
630-
CreateRefreshTokenSession(propagatedContext, gomock.Any(), gomock.Any()).
630+
CreateRefreshTokenSession(propagatedContext, gomock.Any(), gomock.Any(), gomock.Any()).
631631
Return(nil).
632632
Times(1)
633633
mockTransactional.

handler/oauth2/flow_client_credentials.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,8 @@ func (c *ClientCredentialsGrantHandler) PopulateTokenEndpointResponse(ctx contex
6464
}
6565

6666
atLifespan := fosite.GetEffectiveLifespan(request.GetClient(), fosite.GrantTypeClientCredentials, fosite.AccessToken, c.Config.GetAccessTokenLifespan(ctx))
67-
return c.IssueAccessToken(ctx, atLifespan, request, response)
67+
_, err := c.IssueAccessToken(ctx, atLifespan, request, response)
68+
return err
6869
}
6970

7071
func (c *ClientCredentialsGrantHandler) CanSkipClientAuth(ctx context.Context, requester fosite.AccessRequester) bool {

handler/oauth2/flow_refresh.go

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,6 @@ func (c *RefreshTokenGrantHandler) HandleTokenEndpointRequest(ctx context.Contex
6969
scopeNames := strings.Join(c.Config.GetRefreshTokenScopes(ctx), " or ")
7070
hint := fmt.Sprintf("The OAuth 2.0 Client was not granted scope %s and may thus not perform the 'refresh_token' authorization grant.", scopeNames)
7171
return errorsx.WithStack(fosite.ErrScopeNotGranted.WithHint(hint))
72-
7372
}
7473

7574
// The authorization server MUST ... and ensure that the refresh token was issued to the authenticated client
@@ -134,25 +133,18 @@ func (c *RefreshTokenGrantHandler) PopulateTokenEndpointResponse(ctx context.Con
134133
err = c.handleRefreshTokenEndpointStorageError(ctx, err)
135134
}()
136135

137-
ts, err := c.TokenRevocationStorage.GetRefreshTokenSession(ctx, signature, nil)
138-
if err != nil {
139-
return err
140-
} else if err := c.TokenRevocationStorage.RevokeAccessToken(ctx, ts.GetID()); err != nil {
141-
return err
142-
}
136+
storeReq := requester.Sanitize([]string{})
137+
storeReq.SetID(requester.GetID())
143138

144-
if err := c.TokenRevocationStorage.RevokeRefreshTokenMaybeGracePeriod(ctx, ts.GetID(), signature); err != nil {
139+
if err = c.TokenRevocationStorage.RotateRefreshToken(ctx, requester.GetID(), signature); err != nil {
145140
return err
146141
}
147142

148-
storeReq := requester.Sanitize([]string{})
149-
storeReq.SetID(ts.GetID())
150-
151143
if err = c.TokenRevocationStorage.CreateAccessTokenSession(ctx, accessSignature, storeReq); err != nil {
152144
return err
153145
}
154146

155-
if err = c.TokenRevocationStorage.CreateRefreshTokenSession(ctx, refreshSignature, storeReq); err != nil {
147+
if err = c.TokenRevocationStorage.CreateRefreshTokenSession(ctx, refreshSignature, accessSignature, storeReq); err != nil {
156148
return err
157149
}
158150

0 commit comments

Comments
 (0)