MCPcopy Create free account
hub / github.com/supabase/auth / PKCE

Method PKCE

internal/api/token.go:214–289  ·  view source on GitHub ↗
(ctx context.Context, w http.ResponseWriter, r *http.Request)

Source from the content-addressed store, hash-verified

212}
213
214func (a *API) PKCE(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
215 db := a.db.WithContext(ctx)
216 config := a.config
217 var grantParams models.GrantParams
218
219 // There is a slight problem with this as it will pick-up the
220 // User-Agent and IP addresses from the server if used on the server
221 // side. Currently there's no mechanism to distinguish, but the server
222 // can be told to at least propagate the User-Agent header.
223 grantParams.FillGrantParams(r)
224
225 params := &PKCEGrantParams{}
226 if err := retrieveRequestParams(r, params); err != nil {
227 return err
228 }
229
230 if params.AuthCode == "" || params.CodeVerifier == "" {
231 return apierrors.NewBadRequestError(apierrors.ErrorCodeValidationFailed, "invalid request: both auth code and code verifier should be non-empty")
232 }
233
234 flowState, err := models.FindFlowStateByAuthCode(db, params.AuthCode)
235 // Sanity check in case user ID was not set properly
236 if models.IsNotFoundError(err) || flowState.UserID == nil {
237 return apierrors.NewNotFoundError(apierrors.ErrorCodeFlowStateNotFound, "invalid flow state, no valid flow state found")
238 } else if err != nil {
239 return err
240 }
241 if flowState.IsExpired(a.config.External.FlowStateExpiryDuration) {
242 return apierrors.NewUnprocessableEntityError(apierrors.ErrorCodeFlowStateExpired, "invalid flow state, flow state has expired")
243 }
244
245 user, err := models.FindUserByID(db, *flowState.UserID)
246 if err != nil {
247 return err
248 }
249 if err := flowState.VerifyPKCE(params.CodeVerifier); err != nil {
250 return apierrors.NewBadRequestError(apierrors.ErrorCodeBadCodeVerifier, "%s", err.Error())
251 }
252
253 var token *AccessTokenResponse
254 err = db.Transaction(func(tx *storage.Connection) error {
255 var terr error
256 authMethod, err := models.ParseAuthenticationMethod(flowState.AuthenticationMethod)
257 if err != nil {
258 return err
259 }
260 if terr := models.NewAuditLogEntry(config.AuditLog, r, tx, user, models.LoginAction, "", map[string]interface{}{
261 "provider_type": flowState.ProviderType,
262 }); terr != nil {
263 return terr
264 }
265 token, terr = a.tokenService.IssueRefreshToken(r, w.Header(), tx, user, authMethod, grantParams)
266 if terr != nil {
267 // error type is already handled in issueRefreshToken
268 return terr
269 }
270 token.ProviderAccessToken = flowState.ProviderAccessToken
271 // Because not all providers give out a refresh token

Callers

nothing calls this directly

Calls 15

FillGrantParamsMethod · 0.95
NewBadRequestErrorFunction · 0.92
FindFlowStateByAuthCodeFunction · 0.92
IsNotFoundErrorFunction · 0.92
NewNotFoundErrorFunction · 0.92
FindUserByIDFunction · 0.92
NewAuditLogEntryFunction · 0.92
RecordLoginFunction · 0.92
retrieveRequestParamsFunction · 0.85
sendJSONFunction · 0.85

Tested by

no test coverage detected