1
21
22 package oauth2
23
24 import (
25 "context"
26 "time"
27
28 "github.com/ory/x/errorsx"
29
30 "github.com/ory/fosite/storage"
31
32 "github.com/pkg/errors"
33
34 "github.com/ory/fosite"
35 )
36
37
38
39 func (c *AuthorizeExplicitGrantHandler) HandleTokenEndpointRequest(ctx context.Context, request fosite.AccessRequester) error {
40 if !c.CanHandleTokenEndpointRequest(request) {
41 return errorsx.WithStack(errorsx.WithStack(fosite.ErrUnknownRequest))
42 }
43
44 if !request.GetClient().GetGrantTypes().Has("authorization_code") {
45 return errorsx.WithStack(fosite.ErrUnauthorizedClient.WithHint("The OAuth 2.0 Client is not allowed to use authorization grant \"authorization_code\"."))
46 }
47
48 code := request.GetRequestForm().Get("code")
49 signature := c.AuthorizeCodeStrategy.AuthorizeCodeSignature(code)
50 authorizeRequest, err := c.CoreStorage.GetAuthorizeCodeSession(ctx, signature, request.GetSession())
51 if errors.Is(err, fosite.ErrInvalidatedAuthorizeCode) {
52 if authorizeRequest == nil {
53 return fosite.ErrServerError.
54 WithHint("Misconfigured code lead to an error that prohibited the OAuth 2.0 Framework from processing this request.").
55 WithDebug("GetAuthorizeCodeSession must return a value for \"fosite.Requester\" when returning \"ErrInvalidatedAuthorizeCode\".")
56 }
57
58
59 reqID := authorizeRequest.GetID()
60 hint := "The authorization code has already been used."
61 debug := ""
62 if revErr := c.TokenRevocationStorage.RevokeAccessToken(ctx, reqID); revErr != nil {
63 hint += " Additionally, an error occurred during processing the access token revocation."
64 debug += "Revocation of access_token lead to error " + revErr.Error() + "."
65 }
66 if revErr := c.TokenRevocationStorage.RevokeRefreshToken(ctx, reqID); revErr != nil {
67 hint += " Additionally, an error occurred during processing the refresh token revocation."
68 debug += "Revocation of refresh_token lead to error " + revErr.Error() + "."
69 }
70 return errorsx.WithStack(fosite.ErrInvalidGrant.WithHint(hint).WithDebug(debug))
71 } else if err != nil && errors.Is(err, fosite.ErrNotFound) {
72 return errorsx.WithStack(fosite.ErrInvalidGrant.WithWrap(err).WithDebug(err.Error()))
73 } else if err != nil {
74 return errorsx.WithStack(fosite.ErrServerError.WithWrap(err).WithDebug(err.Error()))
75 }
76
77
78
79 if err := c.AuthorizeCodeStrategy.ValidateAuthorizeCode(ctx, request, code); err != nil {
80 return errorsx.WithStack(fosite.ErrInvalidGrant.WithWrap(err).WithDebug(err.Error()))
81 }
82
83
84 request.SetRequestedScopes(authorizeRequest.GetRequestedScopes())
85
86
87 request.SetRequestedAudience(authorizeRequest.GetRequestedAudience())
88
89
90
91
92 if authorizeRequest.GetClient().GetID() != request.GetClient().GetID() {
93 return errorsx.WithStack(fosite.ErrInvalidGrant.WithHint("The OAuth 2.0 Client ID from this request does not match the one from the authorize request."))
94 }
95
96
97
98
99
100 forcedRedirectURI := authorizeRequest.GetRequestForm().Get("redirect_uri")
101 if forcedRedirectURI != "" && forcedRedirectURI != request.GetRequestForm().Get("redirect_uri") {
102 return errorsx.WithStack(fosite.ErrInvalidGrant.WithHint("The \"redirect_uri\" from this request does not match the one from the authorize request."))
103 }
104
105
106
107
108
109
110 request.SetSession(authorizeRequest.GetSession())
111 request.SetID(authorizeRequest.GetID())
112
113 request.GetSession().SetExpiresAt(fosite.AccessToken, time.Now().UTC().Add(c.AccessTokenLifespan).Round(time.Second))
114 if c.RefreshTokenLifespan > -1 {
115 request.GetSession().SetExpiresAt(fosite.RefreshToken, time.Now().UTC().Add(c.RefreshTokenLifespan).Round(time.Second))
116 }
117
118 return nil
119 }
120
121 func canIssueRefreshToken(c *AuthorizeExplicitGrantHandler, request fosite.Requester) bool {
122
123 if len(c.RefreshTokenScopes) > 0 && !request.GetGrantedScopes().HasOneOf(c.RefreshTokenScopes...) {
124 return false
125 }
126
127 if !request.GetClient().GetGrantTypes().Has("refresh_token") {
128 return false
129 }
130 return true
131 }
132
133 func (c *AuthorizeExplicitGrantHandler) PopulateTokenEndpointResponse(ctx context.Context, requester fosite.AccessRequester, responder fosite.AccessResponder) (err error) {
134 if !c.CanHandleTokenEndpointRequest(requester) {
135 return errorsx.WithStack(fosite.ErrUnknownRequest)
136 }
137
138 code := requester.GetRequestForm().Get("code")
139 signature := c.AuthorizeCodeStrategy.AuthorizeCodeSignature(code)
140 authorizeRequest, err := c.CoreStorage.GetAuthorizeCodeSession(ctx, signature, requester.GetSession())
141 if err != nil {
142 return errorsx.WithStack(fosite.ErrServerError.WithWrap(err).WithDebug(err.Error()))
143 } else if err := c.AuthorizeCodeStrategy.ValidateAuthorizeCode(ctx, requester, code); err != nil {
144
145 return errorsx.WithStack(fosite.ErrInvalidRequest.WithWrap(err).WithDebug(err.Error()))
146 }
147
148 for _, scope := range authorizeRequest.GetGrantedScopes() {
149 requester.GrantScope(scope)
150 }
151
152 for _, audience := range authorizeRequest.GetGrantedAudience() {
153 requester.GrantAudience(audience)
154 }
155
156 access, accessSignature, err := c.AccessTokenStrategy.GenerateAccessToken(ctx, requester)
157 if err != nil {
158 return errorsx.WithStack(fosite.ErrServerError.WithWrap(err).WithDebug(err.Error()))
159 }
160
161 var refresh, refreshSignature string
162 if canIssueRefreshToken(c, authorizeRequest) {
163 refresh, refreshSignature, err = c.RefreshTokenStrategy.GenerateRefreshToken(ctx, requester)
164 if err != nil {
165 return errorsx.WithStack(fosite.ErrServerError.WithWrap(err).WithDebug(err.Error()))
166 }
167 }
168
169 ctx, err = storage.MaybeBeginTx(ctx, c.CoreStorage)
170 if err != nil {
171 return errorsx.WithStack(fosite.ErrServerError.WithWrap(err).WithDebug(err.Error()))
172 }
173 defer func() {
174 if err != nil {
175 if rollBackTxnErr := storage.MaybeRollbackTx(ctx, c.CoreStorage); rollBackTxnErr != nil {
176 err = errorsx.WithStack(fosite.ErrServerError.WithWrap(err).WithDebugf("error: %s; rollback error: %s", err, rollBackTxnErr))
177 }
178 }
179 }()
180
181 if err = c.CoreStorage.InvalidateAuthorizeCodeSession(ctx, signature); err != nil {
182 return errorsx.WithStack(fosite.ErrServerError.WithWrap(err).WithDebug(err.Error()))
183 } else if err = c.CoreStorage.CreateAccessTokenSession(ctx, accessSignature, requester.Sanitize([]string{})); err != nil {
184 return errorsx.WithStack(fosite.ErrServerError.WithWrap(err).WithDebug(err.Error()))
185 } else if refreshSignature != "" {
186 if err = c.CoreStorage.CreateRefreshTokenSession(ctx, refreshSignature, requester.Sanitize([]string{})); err != nil {
187 return errorsx.WithStack(fosite.ErrServerError.WithWrap(err).WithDebug(err.Error()))
188 }
189 }
190
191 responder.SetAccessToken(access)
192 responder.SetTokenType("bearer")
193 responder.SetExpiresIn(getExpiresIn(requester, fosite.AccessToken, c.AccessTokenLifespan, time.Now().UTC()))
194 responder.SetScopes(requester.GetGrantedScopes())
195 if refresh != "" {
196 responder.SetExtra("refresh_token", refresh)
197 }
198
199 if err = storage.MaybeCommitTx(ctx, c.CoreStorage); err != nil {
200 return errorsx.WithStack(fosite.ErrServerError.WithWrap(err).WithDebug(err.Error()))
201 }
202
203 return nil
204 }
205
206 func (c *AuthorizeExplicitGrantHandler) CanSkipClientAuth(requester fosite.AccessRequester) bool {
207 return false
208 }
209
210 func (c *AuthorizeExplicitGrantHandler) CanHandleTokenEndpointRequest(requester fosite.AccessRequester) bool {
211
212
213 return requester.GetGrantTypes().ExactOne("authorization_code")
214 }
215
View as plain text