Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[pull] master from supabase:master #2

Open
wants to merge 93 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 9 commits
Commits
Show all changes
93 commits
Select commit Hold shift + click to select a range
4351226
fix: add error codes to password login flow (#1721)
kangmingtay Aug 15, 2024
b2b1123
fix: redirect invalid state errors to site url (#1722)
kangmingtay Aug 16, 2024
0658bbe
chore: updated regex for provider name (#1723)
hiteshbedre Aug 19, 2024
53c11d1
fix: ignore errors if transaction has closed already (#1726)
kangmingtay Aug 20, 2024
a9ff361
feat: Vercel marketplace OIDC (#1731)
MildTomato Aug 21, 2024
dc2391d
fix: custom SMS does not work with Twilio Verify (#1733)
hf Aug 21, 2024
66fd0c8
fix: use signing jwk to sign oauth state (#1728)
kangmingtay Aug 21, 2024
a6de8c9
chore(master): release 2.159.0 (#1716)
github-actions[bot] Aug 21, 2024
60cfb60
fix: return oauth identity when user is created (#1736)
kangmingtay Aug 23, 2024
10fa347
chore(master): release 2.159.1 (#1737)
github-actions[bot] Aug 23, 2024
2d51956
fix: allow anonymous user to update password (#1739)
kangmingtay Aug 26, 2024
c6efec4
fix: remove server side cookie token methods (#1742)
J0 Aug 28, 2024
7e38f4c
fix: hide hook name (#1743)
J0 Aug 28, 2024
d03a54e
chore(master): release 2.159.2 (#1741)
github-actions[bot] Aug 28, 2024
bf276ab
fix: apply shared limiters before email / sms is sent (#1748)
kangmingtay Aug 28, 2024
c5480ef
feat: add support for saml encrypted assertions (#1752)
hf Sep 2, 2024
2ad0737
feat: add option to disable magic links (#1756)
hf Sep 2, 2024
f3a28d1
feat: add authorized email address support (#1757)
hf Sep 2, 2024
0084625
fix: simplify WaitForCleanup (#1747)
LashaJini Sep 2, 2024
7009202
chore(master): release 2.160.0 (#1749)
github-actions[bot] Sep 2, 2024
9d419b4
fix: user sanitization should clean up email change info too (#1759)
staaldraad Sep 3, 2024
a6c1824
chore: fix gosec warnings via ignore annotations in comments (#1770)
cstockton Sep 9, 2024
7e472ad
fix: add token to hook payload for non-secure email change (#1763)
J0 Sep 11, 2024
567ea7e
fix: update mfa admin methods (#1774)
J0 Sep 12, 2024
77d5897
feat: add webauthn configuration variables (#1773)
J0 Sep 13, 2024
25d9874
fix: update aal requirements to update user (#1766)
J0 Sep 17, 2024
c2b2f96
fix: add additional information around errors for missing content typ…
J0 Sep 18, 2024
6ee0091
feat: config reloading (#1771)
cstockton Sep 24, 2024
ed91c59
feat: add `x-sb-error-code` header, show error code in logs (#1765)
hf Sep 24, 2024
5b03fda
chore(master): release 2.161.0 (#1760)
github-actions[bot] Sep 24, 2024
7a5411f
fix: magiclink failing due to passwordStrength check (#1769)
klajdi369 Sep 24, 2024
ba00f75
feat: add support for migration of firebase scrypt passwords (#1768)
J0 Sep 26, 2024
1af203f
fix: apply authorized email restriction to non-admin routes (#1778)
kangmingtay Sep 27, 2024
2c13a7f
chore(master): release 2.162.0 (#1777)
github-actions[bot] Sep 27, 2024
9ac2ea0
fix: bypass check for token & verify endpoints (#1785)
kangmingtay Oct 3, 2024
85d400a
chore(master): release 2.162.1 (#1786)
github-actions[bot] Oct 3, 2024
97a48f6
fix: upgrade ci Go version (#1782)
J0 Oct 3, 2024
819dabb
ci: update openapi spec for saml and generate_link (#1783)
J0 Oct 3, 2024
410b8ac
fix: refactor mfa validation into functions (#1780)
J0 Oct 3, 2024
2e9b144
fix: validateEmail should normalise emails (#1790)
kangmingtay Oct 5, 2024
56e3d33
chore(master): release 2.162.2 (#1787)
github-actions[bot] Oct 5, 2024
aeb5d8f
fix: add twilio verify support on mfa (#1714)
J0 Oct 9, 2024
7f006b6
fix: fix `getExcludedColumns` slice allocation (#1788)
cuishuang Oct 10, 2024
0a3968b
feat: preserve rate limiters in memory across configuration reloads (…
cstockton Oct 10, 2024
646dc66
fix: Fix reqPath for bypass check for verify EP (#1789)
angelolamonaca Oct 11, 2024
8cc2f0e
feat: add MFA for WebAuthn (#1775)
J0 Oct 11, 2024
5e94047
feat: configurable email and sms rate limiting (#1800)
cstockton Oct 14, 2024
fa6f729
fix: inline mailme package for easy development (#1803)
hf Oct 14, 2024
3af03be
fix: email header setting no longer misleading (#1802)
hf Oct 14, 2024
99d6a13
feat: add mail header support via `GOTRUE_SMTP_HEADERS` with `$messag…
hf Oct 14, 2024
9354b83
feat: mailer logging (#1805)
cstockton Oct 15, 2024
c0c5b23
fix: enforce authorized address checks on send email only (#1806)
hf Oct 15, 2024
14b375f
chore(master): release 2.163.0 (#1794)
github-actions[bot] Oct 15, 2024
4f6a461
fix: external host validation (#1808)
hf Oct 22, 2024
39459c1
chore(master): release 2.163.1 (#1809)
github-actions[bot] Oct 22, 2024
9ce2340
fix: ignore rate limits for autoconfirm (#1810)
kangmingtay Oct 22, 2024
6ac5624
chore(master): release 2.163.2 (#1811)
github-actions[bot] Oct 22, 2024
26d2e36
feat: return validation failed error if captcha request was not json …
hf Oct 25, 2024
158e473
fix: make drop_uniqueness_constraint_on_phone idempotent (#1817)
kangmingtay Oct 28, 2024
3b03472
chore: use retrieveRequestParams where possible (#1818)
kangmingtay Oct 28, 2024
fa020d0
fix: improve error messaging for http hooks (#1821)
kangmingtay Oct 28, 2024
a7129df
fix: possible panic if refresh token has a null session_id (#1822)
kangmingtay Oct 30, 2024
4614dc5
fix: add error codes to refresh token flow (#1824)
kangmingtay Nov 1, 2024
635d9ba
chore(deps): bump github.com/golang-jwt/jwt/v4 from 4.4.3 to 4.5.1 (#…
dependabot[bot] Nov 5, 2024
0a589d0
fix: correct web authn aaguid column naming (#1826)
J0 Nov 6, 2024
7c3cf26
fix: add test coverage for rate limits with 0 permitted events (#1834)
cstockton Nov 11, 2024
9ce2857
fix: default to files:read scope for Figma provider (#1831)
smogg Nov 12, 2024
cb7894e
fix: rate limits of 0 take precedence over MAILER_AUTO_CONFIRM (#1837)
cstockton Nov 13, 2024
a616451
chore(master): release 2.164.0 (#1816)
github-actions[bot] Nov 15, 2024
7de6bfb
ci: upload release artifact to supabase s3 bucket (#1812)
hf Nov 20, 2024
e358da5
feat: use embedded migrations for `migrate` command (#1843)
hf Nov 27, 2024
49fbbf0
fix: update ip mismatch error message (#1849)
J0 Nov 28, 2024
1bad34e
Revert "ci: upload release artifact to supabase s3 bucket" (#1854)
kangmingtay Dec 3, 2024
834a380
fix: return the error code instead of status code (#1855)
kangmingtay Dec 4, 2024
b33bc31
fix: fallback on btree indexes when hash is unavailable (#1856)
olirice Dec 4, 2024
307d6ee
chore: update check conventional-commits (#1857)
staaldraad Dec 4, 2024
1c7202f
fix: revert fallback on btree indexes when hash is unavailable (#1858)
J0 Dec 4, 2024
2c291f0
feat: add email validation function to lower bounce rates (#1845)
cstockton Dec 5, 2024
a19d62d
chore(master): release 2.165.0 (#1846)
github-actions[bot] Dec 5, 2024
9fe5b1e
fix: Revert "fix: revert fallback on btree indexes when hash is unava…
olirice Dec 6, 2024
40e0de1
chore(deps): bump golang.org/x/crypto from 0.26.0 to 0.31.0 (#1869)
dependabot[bot] Dec 12, 2024
483463e
fix: email_verified field not being updated on signup confirmation (#…
kangmingtay Dec 12, 2024
a6918f4
fix: handle user banned error code (#1851)
J0 Dec 13, 2024
fd82601
fix: check if session is nil (#1873)
kangmingtay Dec 13, 2024
a3eecd1
chore: merge release/2.165.0 into master (#1875)
cstockton Dec 16, 2024
f572ced
fix: skip cleanup for non-2xx status (#1877)
kangmingtay Dec 19, 2024
11a312f
feat: switch to googleapis/release-please-action, bump to 2.166.0 (#1…
hf Dec 23, 2024
6de1e19
chore(master): release 2.166.0 (#1884)
github-actions[bot] Dec 23, 2024
9dbe6ef
feat: fix argon2 parsing and comparison (#1887)
hf Dec 24, 2024
9c97b8e
chore(master): release 2.167.0 (#1888)
github-actions[bot] Dec 24, 2024
7b83c4b
docs: change coveralls image in README (#1889)
hf Dec 24, 2024
4faea5a
ci: fix coverage metering by removing files not under test (#1890)
hf Dec 24, 2024
a7f1c6e
ci: use `alpine:3` as base image (#1894)
hf Dec 27, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,23 @@
# Changelog

## [2.159.0](https://github.com/supabase/auth/compare/v2.158.1...v2.159.0) (2024-08-21)


### Features

* Vercel marketplace OIDC ([#1731](https://github.com/supabase/auth/issues/1731)) ([a9ff361](https://github.com/supabase/auth/commit/a9ff3612196af4a228b53a8bfb9c11785bcfba8d))


### Bug Fixes

* add error codes to password login flow ([#1721](https://github.com/supabase/auth/issues/1721)) ([4351226](https://github.com/supabase/auth/commit/435122627a0784f1c5cb76d7e08caa1f6259423b))
* change phone constraint to per user ([#1713](https://github.com/supabase/auth/issues/1713)) ([b9bc769](https://github.com/supabase/auth/commit/b9bc769b93b6e700925fcbc1ebf8bf9678034205))
* custom SMS does not work with Twilio Verify ([#1733](https://github.com/supabase/auth/issues/1733)) ([dc2391d](https://github.com/supabase/auth/commit/dc2391d15f2c0725710aa388cd32a18797e6769c))
* ignore errors if transaction has closed already ([#1726](https://github.com/supabase/auth/issues/1726)) ([53c11d1](https://github.com/supabase/auth/commit/53c11d173a79ae5c004871b1b5840c6f9425a080))
* redirect invalid state errors to site url ([#1722](https://github.com/supabase/auth/issues/1722)) ([b2b1123](https://github.com/supabase/auth/commit/b2b11239dc9f9bd3c85d76f6c23ee94beb3330bb))
* remove TOTP field for phone enroll response ([#1717](https://github.com/supabase/auth/issues/1717)) ([4b04327](https://github.com/supabase/auth/commit/4b043275dd2d94600a8138d4ebf4638754ed926b))
* use signing jwk to sign oauth state ([#1728](https://github.com/supabase/auth/issues/1728)) ([66fd0c8](https://github.com/supabase/auth/commit/66fd0c8434388bbff1e1bf02f40517aca0e9d339))

## [2.158.1](https://github.com/supabase/auth/compare/v2.158.0...v2.158.1) (2024-08-05)


Expand Down
2 changes: 1 addition & 1 deletion internal/api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,7 @@ func NewAPIWithVersion(globalConfig *conf.GlobalConfiguration, db *storage.Conne
tollbooth.NewLimiter(api.config.SAML.RateLimitAssertion/(60*5), &limiter.ExpirableOptions{
DefaultExpirationTTL: time.Hour,
}).SetBurst(30),
)).Post("/acs", api.SAMLACS)
)).Post("/acs", api.SamlAcs)
})
})

Expand Down
4 changes: 3 additions & 1 deletion internal/api/errorcodes.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,5 +81,7 @@ const (
ErrorCodeMFAPhoneVerifyDisabled ErrorCode = "mfa_phone_verify_not_enabled"
ErrorCodeMFATOTPEnrollDisabled ErrorCode = "mfa_totp_enroll_not_enabled"
ErrorCodeMFATOTPVerifyDisabled ErrorCode = "mfa_totp_verify_not_enabled"
ErrorCodeVerifiedFactorExists ErrorCode = "mfa_verified_factor_exists"
ErrorCodeMFAVerifiedFactorExists ErrorCode = "mfa_verified_factor_exists"
//#nosec G101 -- Not a secret value.
ErrorCodeInvalidCredentials ErrorCode = "invalid_credentials"
)
43 changes: 33 additions & 10 deletions internal/api/external.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
jwt "github.com/golang-jwt/jwt/v5"
"github.com/sirupsen/logrus"
"github.com/supabase/auth/internal/api/provider"
"github.com/supabase/auth/internal/conf"
"github.com/supabase/auth/internal/models"
"github.com/supabase/auth/internal/observability"
"github.com/supabase/auth/internal/storage"
Expand Down Expand Up @@ -106,8 +107,7 @@ func (a *API) GetExternalProviderRedirectURL(w http.ResponseWriter, r *http.Requ
claims.LinkingTargetID = linkingTargetUser.ID.String()
}

token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
tokenString, err := token.SignedString([]byte(config.JWT.Secret))
tokenString, err := signJwt(&config.JWT, claims)
if err != nil {
return "", internalServerError("Error creating state").WithInternalError(err)
}
Expand Down Expand Up @@ -138,7 +138,7 @@ func (a *API) ExternalProviderCallback(w http.ResponseWriter, r *http.Request) e
if err != nil {
return err
}
a.redirectErrors(a.internalExternalProviderCallback, w, r, u)
redirectErrors(a.internalExternalProviderCallback, w, r, u)
return nil
}

Expand Down Expand Up @@ -338,7 +338,7 @@ func (a *API) createAccountFromExternalIdentity(tx *storage.Connection, r *http.
if identity, terr = a.createNewIdentity(tx, user, providerType, identityData); terr != nil {
return nil, terr
}

user.Identities = append(user.Identities, *identity)
case models.AccountExists:
user = decision.User
identity = decision.Identities[0]
Expand Down Expand Up @@ -478,18 +478,39 @@ func (a *API) processInvite(r *http.Request, tx *storage.Connection, userData *p
return user, nil
}

func (a *API) loadExternalState(ctx context.Context, state string) (context.Context, error) {
func (a *API) loadExternalState(ctx context.Context, r *http.Request) (context.Context, error) {
var state string
switch r.Method {
case http.MethodPost:
state = r.FormValue("state")
default:
state = r.URL.Query().Get("state")
}
if state == "" {
return ctx, badRequestError(ErrorCodeBadOAuthCallback, "OAuth state parameter missing")
}
config := a.config
claims := ExternalProviderClaims{}
p := jwt.NewParser(jwt.WithValidMethods([]string{jwt.SigningMethodHS256.Name}))
p := jwt.NewParser(jwt.WithValidMethods(config.JWT.ValidMethods))
_, err := p.ParseWithClaims(state, &claims, func(token *jwt.Token) (interface{}, error) {
return []byte(config.JWT.Secret), nil
if kid, ok := token.Header["kid"]; ok {
if kidStr, ok := kid.(string); ok {
return conf.FindPublicKeyByKid(kidStr, &config.JWT)
}
}
if alg, ok := token.Header["alg"]; ok {
if alg == jwt.SigningMethodHS256.Name {
// preserve backward compatibility for cases where the kid is not set
return []byte(config.JWT.Secret), nil
}
}
return nil, fmt.Errorf("missing kid")
})
if err != nil {
return nil, badRequestError(ErrorCodeBadOAuthState, "OAuth callback with invalid state").WithInternalError(err)
return ctx, badRequestError(ErrorCodeBadOAuthState, "OAuth callback with invalid state").WithInternalError(err)
}
if claims.Provider == "" {
return nil, badRequestError(ErrorCodeBadOAuthState, "OAuth callback with invalid state (missing provider)")
return ctx, badRequestError(ErrorCodeBadOAuthState, "OAuth callback with invalid state (missing provider)")
}
if claims.InviteToken != "" {
ctx = withInviteToken(ctx, claims.InviteToken)
Expand Down Expand Up @@ -564,6 +585,8 @@ func (a *API) Provider(ctx context.Context, name string, scopes string) (provide
return provider.NewTwitchProvider(config.External.Twitch, scopes)
case "twitter":
return provider.NewTwitterProvider(config.External.Twitter, scopes)
case "vercel_marketplace":
return provider.NewVercelMarketplaceProvider(config.External.VercelMarketplace, scopes)
case "workos":
return provider.NewWorkOSProvider(config.External.WorkOS)
case "zoom":
Expand All @@ -573,7 +596,7 @@ func (a *API) Provider(ctx context.Context, name string, scopes string) (provide
}
}

func (a *API) redirectErrors(handler apiHandler, w http.ResponseWriter, r *http.Request, u *url.URL) {
func redirectErrors(handler apiHandler, w http.ResponseWriter, r *http.Request, u *url.URL) {
ctx := r.Context()
log := observability.GetLogEntry(r).Entry
errorID := utilities.GetRequestID(ctx)
Expand Down
28 changes: 16 additions & 12 deletions internal/api/external_oauth.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"github.com/sirupsen/logrus"
"github.com/supabase/auth/internal/api/provider"
"github.com/supabase/auth/internal/observability"
"github.com/supabase/auth/internal/utilities"
)

// OAuthProviderData contains the userData and token returned by the oauth provider
Expand All @@ -23,17 +24,6 @@ type OAuthProviderData struct {
// loadFlowState parses the `state` query parameter as a JWS payload,
// extracting the provider requested
func (a *API) loadFlowState(w http.ResponseWriter, r *http.Request) (context.Context, error) {
var state string
if r.Method == http.MethodPost {
state = r.FormValue("state")
} else {
state = r.URL.Query().Get("state")
}

if state == "" {
return nil, badRequestError(ErrorCodeBadOAuthCallback, "OAuth state parameter missing")
}

ctx := r.Context()
oauthToken := r.URL.Query().Get("oauth_token")
if oauthToken != "" {
Expand All @@ -43,7 +33,21 @@ func (a *API) loadFlowState(w http.ResponseWriter, r *http.Request) (context.Con
if oauthVerifier != "" {
ctx = withOAuthVerifier(ctx, oauthVerifier)
}
return a.loadExternalState(ctx, state)

var err error
ctx, err = a.loadExternalState(ctx, r)
if err != nil {
u, uerr := url.ParseRequestURI(a.config.SiteURL)
if uerr != nil {
return ctx, internalServerError("site url is improperly formatted").WithInternalError(uerr)
}

q := getErrorQueryString(err, utilities.GetRequestID(ctx), observability.GetLogEntry(r).Entry, u.Query())
u.RawQuery = q.Encode()

http.Redirect(w, r, u.String(), http.StatusSeeOther)
}
return ctx, err
}

func (a *API) oAuthCallback(ctx context.Context, r *http.Request, providerType string) (*OAuthProviderData, error) {
Expand Down
2 changes: 1 addition & 1 deletion internal/api/external_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ func (ts *ExternalTestSuite) TestRedirectErrorsShouldPreserveParams() {
parsedURL, err := url.Parse(c.RedirectURL)
require.Equal(ts.T(), err, nil)

ts.API.redirectErrors(ts.API.internalExternalProviderCallback, w, req, parsedURL)
redirectErrors(ts.API.internalExternalProviderCallback, w, req, parsedURL)

parsedParams, err := url.ParseQuery(parsedURL.RawQuery)
require.Equal(ts.T(), err, nil)
Expand Down
31 changes: 31 additions & 0 deletions internal/api/jwks.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ package api
import (
"net/http"

jwt "github.com/golang-jwt/jwt/v5"
"github.com/lestrrat-go/jwx/v2/jwa"
jwk "github.com/lestrrat-go/jwx/v2/jwk"
"github.com/supabase/auth/internal/conf"
)

type JwksResponse struct {
Expand All @@ -28,3 +30,32 @@ func (a *API) Jwks(w http.ResponseWriter, r *http.Request) error {
w.Header().Set("Cache-Control", "public, max-age=600")
return sendJSON(w, http.StatusOK, resp)
}

func signJwt(config *conf.JWTConfiguration, claims jwt.Claims) (string, error) {
signingJwk, err := conf.GetSigningJwk(config)
if err != nil {
return "", err
}
signingMethod := conf.GetSigningAlg(signingJwk)
token := jwt.NewWithClaims(signingMethod, claims)
if token.Header == nil {
token.Header = make(map[string]interface{})
}

if _, ok := token.Header["kid"]; !ok {
if kid := signingJwk.KeyID(); kid != "" {
token.Header["kid"] = kid
}
}
// this serializes the aud claim to a string
jwt.MarshalSingleStringAsArray = false
signingKey, err := conf.GetSigningKey(signingJwk)
if err != nil {
return "", err
}
signed, err := token.SignedString(signingKey)
if err != nil {
return "", err
}
return signed, nil
}
2 changes: 1 addition & 1 deletion internal/api/mfa.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ func (a *API) enrollPhoneFactor(w http.ResponseWriter, r *http.Request, params *
if factor.Phone.String() == phone {
if factor.IsVerified() {
return unprocessableEntityError(
ErrorCodeVerifiedFactorExists,
ErrorCodeMFAVerifiedFactorExists,
"A verified phone factor already exists, unenroll the existing factor to continue",
)
} else if factor.IsUnverified() {
Expand Down
36 changes: 36 additions & 0 deletions internal/api/provider/oidc.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ func ParseIDToken(ctx context.Context, provider *oidc.Provider, config *oidc.Con
token, data, err = parseLinkedinIDToken(token)
case IssuerKakao:
token, data, err = parseKakaoIDToken(token)
case IssuerVercelMarketplace:
token, data, err = parseVercelMarketplaceIDToken(token)
default:
if IsAzureIssuer(token.Issuer) {
token, data, err = parseAzureIDToken(token)
Expand Down Expand Up @@ -351,6 +353,40 @@ func parseKakaoIDToken(token *oidc.IDToken) (*oidc.IDToken, *UserProvidedData, e
return token, &data, nil
}

type VercelMarketplaceIDTokenClaims struct {
jwt.RegisteredClaims

UserEmail string `json:"user_email"`
UserName string `json:"user_name"`
UserAvatarUrl string `json:"user_avatar_url"`
}

func parseVercelMarketplaceIDToken(token *oidc.IDToken) (*oidc.IDToken, *UserProvidedData, error) {
var claims VercelMarketplaceIDTokenClaims

if err := token.Claims(&claims); err != nil {
return nil, nil, err
}

var data UserProvidedData

data.Emails = append(data.Emails, Email{
Email: claims.UserEmail,
Verified: true,
Primary: true,
})

data.Metadata = &Claims{
Issuer: token.Issuer,
Subject: token.Subject,
ProviderId: token.Subject,
Name: claims.UserName,
Picture: claims.UserAvatarUrl,
}

return token, &data, nil
}

func parseGenericIDToken(token *oidc.IDToken) (*oidc.IDToken, *UserProvidedData, error) {
var data UserProvidedData

Expand Down
78 changes: 78 additions & 0 deletions internal/api/provider/vercel_marketplace.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package provider

import (
"context"
"errors"
"strings"

"github.com/coreos/go-oidc/v3/oidc"
"github.com/supabase/auth/internal/conf"
"golang.org/x/oauth2"
)

const (
defaultVercelMarketplaceAPIBase = "api.vercel.com"
IssuerVercelMarketplace = "https://marketplace.vercel.com"
)

type vercelMarketplaceProvider struct {
*oauth2.Config
oidc *oidc.Provider
APIPath string
}

// NewVercelMarketplaceProvider creates a VercelMarketplace account provider via OIDC.
func NewVercelMarketplaceProvider(ext conf.OAuthProviderConfiguration, scopes string) (OAuthProvider, error) {
if err := ext.ValidateOAuth(); err != nil {
return nil, err
}

apiPath := chooseHost(ext.URL, defaultVercelMarketplaceAPIBase)

oauthScopes := []string{}

if scopes != "" {
oauthScopes = append(oauthScopes, strings.Split(scopes, ",")...)
}

oidcProvider, err := oidc.NewProvider(context.Background(), IssuerVercelMarketplace)
if err != nil {
return nil, err
}

return &vercelMarketplaceProvider{
oidc: oidcProvider,
Config: &oauth2.Config{
ClientID: ext.ClientID[0],
ClientSecret: ext.Secret,
Endpoint: oauth2.Endpoint{
AuthURL: apiPath + "/oauth/v2/authorization",
TokenURL: apiPath + "/oauth/v2/accessToken",
},
Scopes: oauthScopes,
RedirectURL: ext.RedirectURI,
},
APIPath: apiPath,
}, nil
}

func (g vercelMarketplaceProvider) GetOAuthToken(code string) (*oauth2.Token, error) {
return g.Exchange(context.Background(), code)
}

func (g vercelMarketplaceProvider) GetUserData(ctx context.Context, tok *oauth2.Token) (*UserProvidedData, error) {
idToken := tok.Extra("id_token")
if tok.AccessToken == "" || idToken == nil {
return nil, errors.New("vercel_marketplace: no OIDC ID token present in response")
}

_, data, err := ParseIDToken(ctx, g.oidc, &oidc.Config{
ClientID: g.ClientID,
}, idToken.(string), ParseIDTokenOptions{
AccessToken: tok.AccessToken,
})
if err != nil {
return nil, err
}
return data, nil
}
Loading