MCPcopy Index your code
hub / github.com/supabase/auth / PasskeyAuthenticationVerify

Method PasskeyAuthenticationVerify

internal/api/passkey_authentication.go:69–206  ·  view source on GitHub ↗

PasskeyAuthenticationVerify handles POST /passkeys/authentication/verify. Validates the WebAuthn assertion and issues tokens for discoverable credential login.

(w http.ResponseWriter, r *http.Request)

Source from the content-addressed store, hash-verified

67// PasskeyAuthenticationVerify handles POST /passkeys/authentication/verify.
68// Validates the WebAuthn assertion and issues tokens for discoverable credential login.
69func (a *API) PasskeyAuthenticationVerify(w http.ResponseWriter, r *http.Request) error {
70 ctx := r.Context()
71 config := a.config
72 db := a.db.WithContext(ctx)
73
74 params := &PasskeyAuthenticationVerifyParams{}
75 body, err := utilities.GetBodyBytes(r)
76 if err != nil {
77 return apierrors.NewBadRequestError(apierrors.ErrorCodeBadJSON, "Could not read request body")
78 }
79 if err := json.Unmarshal(body, params); err != nil {
80 return apierrors.NewBadRequestError(apierrors.ErrorCodeBadJSON, "Could not parse request body as JSON: %v", err)
81 }
82
83 if params.ChallengeID == "" {
84 return apierrors.NewBadRequestError(apierrors.ErrorCodeValidationFailed, "challenge_id is required")
85 }
86 if params.Credential == nil {
87 return apierrors.NewBadRequestError(apierrors.ErrorCodeValidationFailed, "credential is required")
88 }
89
90 challengeID, err := uuid.FromString(params.ChallengeID)
91 if err != nil {
92 return apierrors.NewBadRequestError(apierrors.ErrorCodeValidationFailed, "challenge_id must be a valid UUID")
93 }
94
95 challenge, err := models.ConsumeWebAuthnChallengeByID(db, challengeID, models.WebAuthnChallengeTypeAuthentication, nil)
96 if err != nil {
97 if models.IsNotFoundError(err) {
98 return apierrors.NewBadRequestError(apierrors.ErrorCodeWebAuthnChallengeNotFound, "Challenge not found or already used")
99 }
100
101 return apierrors.NewInternalServerError("Database error consuming challenge").WithInternalError(err)
102 }
103
104 if challenge.IsExpired() {
105 return apierrors.NewBadRequestError(apierrors.ErrorCodeWebAuthnChallengeExpired, "Challenge has expired")
106 }
107
108 parsedResponse, err := parseCredentialAssertionResponse(params.Credential)
109 if err != nil {
110 return apierrors.NewBadRequestError(apierrors.ErrorCodeWebAuthnVerificationFailed, "Invalid credential response").WithInternalError(err)
111 }
112
113 webAuthn, err := a.getPasskeyWebAuthn()
114 if err != nil {
115 return apierrors.NewInternalServerError("Failed to initialize WebAuthn").WithInternalError(err)
116 }
117
118 sessionData := *challenge.SessionData.SessionData
119
120 // Discoverable login: resolve user from userHandle in the assertion
121 handler := func(rawID, userHandle []byte) (webauthn.User, error) {
122 userID, uerr := uuid.FromString(string(userHandle))
123 if uerr != nil {
124 return nil, uerr
125 }
126

Callers

nothing calls this directly

Calls 15

getPasskeyWebAuthnMethod · 0.95
FillGrantParamsMethod · 0.95
issueRefreshTokenMethod · 0.95
GetBodyBytesFunction · 0.92
NewBadRequestErrorFunction · 0.92
IsNotFoundErrorFunction · 0.92
NewInternalServerErrorFunction · 0.92
FindUserByIDFunction · 0.92
NewForbiddenErrorFunction · 0.92

Tested by

no test coverage detected