Repository: supabase/gotrue
Pull request #1198 (2023-07-24 12:26:41)

feat: update github.com/rs/cors to v1.9.0
Was not using the latest version.


Patch:
diff --git a/go.mod b/go.mod
index 989fece5..d9176ffe 100644
--- a/go.mod
+++ b/go.mod
@@ -26,7 +26,7 @@ require (
 	github.com/mrjones/oauth v0.0.0-20190623134757-126b35219450
 	github.com/pkg/errors v0.9.1
 	github.com/pquerna/otp v1.3.0
-	github.com/rs/cors v1.6.0
+	github.com/rs/cors v1.9.0
 	github.com/sebest/xff v0.0.0-20160910043805-6c115e0ffa35
 	github.com/sethvargo/go-password v0.2.0
 	github.com/sirupsen/logrus v1.9.3
diff --git a/go.sum b/go.sum
index 8095486c..66af8890 100644
--- a/go.sum
+++ b/go.sum
@@ -435,6 +435,8 @@ github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZV
 github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
 github.com/rs/cors v1.6.0 h1:G9tHG9lebljV9mfp9SNPDL36nCDxmo3zTlAf1YgvzmI=
 github.com/rs/cors v1.6.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
+github.com/rs/cors v1.9.0 h1:l9HGsTsHJcvW14Nk7J9KFz8bzeAWXn3CG6bgt7LsrAE=
+github.com/rs/cors v1.9.0/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU=
 github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
 github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU=
 github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc=
diff --git a/internal/api/token.go b/internal/api/token.go
index 77abf34d..fa7dae29 100644
--- a/internal/api/token.go
+++ b/internal/api/token.go
@@ -36,6 +36,7 @@ type AccessTokenResponse struct {
 	Token                string       `json:"access_token"`
 	TokenType            string       `json:"token_type"` // Bearer
 	ExpiresIn            int          `json:"expires_in"`
+	ExpiresAt            int64        `json:"expires_at"`
 	RefreshToken         string       `json:"refresh_token"`
 	User                 *models.User `json:"user"`
 	ProviderAccessToken  string       `json:"provider_token,omitempty"`
@@ -48,6 +49,7 @@ func (r *AccessTokenResponse) AsRedirectURL(redirectURL string, extraParams url.
 	extraParams.Set("access_token", r.Token)
 	extraParams.Set("token_type", r.TokenType)
 	extraParams.Set("expires_in", strconv.Itoa(r.ExpiresIn))
+	extraParams.Set("expires_at", strconv.FormatInt(r.ExpiresAt, 10))
 	extraParams.Set("refresh_token", r.RefreshToken)
 
 	return redirectURL + "#" + extraParams.Encode()
@@ -246,29 +248,30 @@ func (a *API) PKCE(ctx context.Context, w http.ResponseWriter, r *http.Request)
 
 }
 
-func generateAccessToken(tx *storage.Connection, user *models.User, sessionId *uuid.UUID, config *conf.JWTConfiguration) (string, error) {
+func generateAccessToken(tx *storage.Connection, user *models.User, sessionId *uuid.UUID, config *conf.JWTConfiguration) (string, int64, error) {
 	aal, amr := models.AAL1.String(), []models.AMREntry{}
 	sid := ""
 	if sessionId != nil {
 		sid = sessionId.String()
 		session, terr := models.FindSessionByID(tx, *sessionId, false)
 		if terr != nil {
-			return "", terr
+			return "", 0, terr
 		}
 		aal, amr, terr = session.CalculateAALAndAMR(tx)
 		if terr != nil {
-			return "", terr
+			return "", 0, terr
 		}
 	}
 
 	issuedAt := time.Now().UTC()
+	expiresAt := issuedAt.Add(time.Second * time.Duration(config.Exp)).Unix()
 
 	claims := &GoTrueClaims{
 		StandardClaims: jwt.StandardClaims{
 			Subject:   user.ID.String(),
 			Audience:  user.Aud,
 			IssuedAt:  issuedAt.Unix(),
-			ExpiresAt: issuedAt.Add(time.Second * time.Duration(config.Exp)).Unix(),
+			ExpiresAt: expiresAt,
 			Issuer:    config.Issuer,
 		},
 		Email:                         user.GetEmail(),
@@ -291,7 +294,12 @@ func generateAccessToken(tx *storage.Connection, user *models.User, sessionId *u
 		token.Header["kid"] = config.KeyID
 	}
 
-	return token.SignedString([]byte(config.Secret))
+	signed, err := token.SignedString([]byte(config.Secret))
+	if err != nil {
+		return "", 0, err
+	}
+
+	return signed, expiresAt, nil
 }
 
 func (a *API) issueRefreshToken(ctx context.Context, conn *storage.Connection, user *models.User, authenticationMethod models.AuthenticationMethod, grantParams models.GrantParams) (*AccessTokenResponse, error) {
@@ -301,6 +309,7 @@ func (a *API) issueRefreshToken(ctx context.Context, conn *storage.Connection, u
 	user.LastSignInAt = &now
 
 	var tokenString string
+	var expiresAt int64
 	var refreshToken *models.RefreshToken
 
 	err := conn.Transaction(func(tx *storage.Connection) error {
@@ -320,7 +329,7 @@ func (a *API) issueRefreshToken(ctx context.Context, conn *storage.Connection, u
 			return terr
 		}
 
-		tokenString, terr = generateAccessToken(tx, user, refreshToken.SessionId, &config.JWT)
+		tokenString, expiresAt, terr = generateAccessToken(tx, user, refreshToken.SessionId, &config.JWT)
 		if terr != nil {
 			return internalServerError("error generating jwt token").WithInternalError(terr)
 		}
@@ -334,6 +343,7 @@ func (a *API) issueRefreshToken(ctx context.Context, conn *storage.Connection, u
 		Token:        tokenString,
 		TokenType:    "bearer",
 		ExpiresIn:    config.JWT.Exp,
+		ExpiresAt:    expiresAt,
 		RefreshToken: refreshToken.Token,
 		User:         user,
 	}, nil
@@ -343,6 +353,7 @@ func (a *API) updateMFASessionAndClaims(r *http.Request, tx *storage.Connection,
 	ctx := r.Context()
 	config := a.config
 	var tokenString string
+	var expiresAt int64
 	var refreshToken *models.RefreshToken
 	currentClaims := getClaims(ctx)
 	sessionId, err := uuid.FromString(currentClaims.SessionId)
@@ -383,7 +394,7 @@ func (a *API) updateMFASessionAndClaims(r *http.Request, tx *storage.Connection,
 			return err
 		}
 
-		tokenString, terr = generateAccessToken(tx, user, &sessionId, &config.JWT)
+		tokenString, expiresAt, terr = generateAccessToken(tx, user, &sessionId, &config.JWT)
 
 		if terr != nil {
 			return internalServerError("error generating jwt token").WithInternalError(terr)
@@ -397,6 +408,7 @@ func (a *API) updateMFASessionAndClaims(r *http.Request, tx *storage.Connection,
 		Token:        tokenString,
 		TokenType:    "bearer",
 		ExpiresIn:    config.JWT.Exp,
+		ExpiresAt:    expiresAt,
 		RefreshToken: refreshToken.Token,
 		User:         user,
 	}, nil
diff --git a/internal/api/token_refresh.go b/internal/api/token_refresh.go
index 85a6aba7..e2bdfca9 100644
--- a/internal/api/token_refresh.go
+++ b/internal/api/token_refresh.go
@@ -64,6 +64,7 @@ func (a *API) RefreshTokenGrant(ctx context.Context, w http.ResponseWriter, r *h
 	// session in a transaction so that there's no concurrent modification
 
 	var tokenString string
+	var expiresAt int64
 	var newTokenResponse *AccessTokenResponse
 
 	err = db.Transaction(func(tx *storage.Connection) error {
@@ -117,7 +118,7 @@ func (a *API) RefreshTokenGrant(ctx context.Context, w http.ResponseWriter, r *h
 			return terr
 		}
 
-		tokenString, terr = generateAccessToken(tx, user, newToken.SessionId, &config.JWT)
+		tokenString, expiresAt, terr = generateAccessToken(tx, user, newToken.SessionId, &config.JWT)
 
 		if terr != nil {
 			return internalServerError("error generating jwt token").WithInternalError(terr)
@@ -127,6 +128,7 @@ func (a *API) RefreshTokenGrant(ctx context.Context, w http.ResponseWriter, r *h
 			Token:        tokenString,
 			TokenType:    "bearer",
 			ExpiresIn:    config.JWT.Exp,
+			ExpiresAt:    expiresAt,
 			RefreshToken: newToken.Token,
 			User:         user,
 		}
diff --git a/openapi.yaml b/openapi.yaml
index 4f5785b2..f23a72fa 100644
--- a/openapi.yaml
+++ b/openapi.yaml
@@ -1893,6 +1893,9 @@ components:
         expires_in:
           type: integer
           description: Number of seconds after which the `access_token` should be renewed by using the refresh token with the `refresh_token` grant type.
+        expires_at:
+          type: integer
+          description: UNIX timestamp after which the `access_token` should be renewed by using the refresh token with the `refresh_token` grant type.
         user:
           $ref: "#/components/schemas/UserSchema"
 


Test patch:
diff --git a/internal/api/audit_test.go b/internal/api/audit_test.go
index baf03d90..2e54db29 100644
--- a/internal/api/audit_test.go
+++ b/internal/api/audit_test.go
@@ -48,7 +48,7 @@ func (ts *AuditTestSuite) makeSuperAdmin(email string) string {
 	u.Role = "supabase_admin"
 
 	var token string
-	token, err = generateAccessToken(ts.API.db, u, nil, &ts.Config.JWT)
+	token, _, err = generateAccessToken(ts.API.db, u, nil, &ts.Config.JWT)
 	require.NoError(ts.T(), err, "Error generating access token")
 
 	p := jwt.Parser{ValidMethods: []string{jwt.SigningMethodHS256.Name}}
diff --git a/internal/api/invite_test.go b/internal/api/invite_test.go
index ba0f0113..62332fd3 100644
--- a/internal/api/invite_test.go
+++ b/internal/api/invite_test.go
@@ -59,7 +59,7 @@ func (ts *InviteTestSuite) makeSuperAdmin(email string) string {
 	u.Role = "supabase_admin"
 
 	var token string
-	token, err = generateAccessToken(ts.API.db, u, nil, &ts.Config.JWT)
+	token, _, err = generateAccessToken(ts.API.db, u, nil, &ts.Config.JWT)
 
 	require.NoError(ts.T(), err, "Error generating access token")
 
diff --git a/internal/api/logout_test.go b/internal/api/logout_test.go
index c873532e..7a9b3ebb 100644
--- a/internal/api/logout_test.go
+++ b/internal/api/logout_test.go
@@ -42,7 +42,7 @@ func (ts *LogoutTestSuite) SetupTest() {
 
 	// generate access token to use for logout
 	var t string
-	t, err = generateAccessToken(ts.API.db, u, nil, &ts.Config.JWT)
+	t, _, err = generateAccessToken(ts.API.db, u, nil, &ts.Config.JWT)
 	require.NoError(ts.T(), err)
 	ts.token = t
 }
diff --git a/internal/api/mfa_test.go b/internal/api/mfa_test.go
index 4df987db..36090e6d 100644
--- a/internal/api/mfa_test.go
+++ b/internal/api/mfa_test.go
@@ -124,7 +124,7 @@ func (ts *MFATestSuite) TestEnrollFactor() {
 			user, err := models.FindUserByEmailAndAudience(ts.API.db, "test@example.com", ts.Config.JWT.Aud)
 			ts.Require().NoError(err)
 
-			token, err := generateAccessToken(ts.API.db, user, nil, &ts.Config.JWT)
+			token, _, err := generateAccessToken(ts.API.db, user, nil, &ts.Config.JWT)
 			require.NoError(ts.T(), err)
 
 			w := httptest.NewRecorder()
@@ -161,7 +161,7 @@ func (ts *MFATestSuite) TestChallengeFactor() {
 	require.NoError(ts.T(), err)
 	f := factors[0]
 
-	token, err := generateAccessToken(ts.API.db, u, nil, &ts.Config.JWT)
+	token, _, err := generateAccessToken(ts.API.db, u, nil, &ts.Config.JWT)
 	require.NoError(ts.T(), err, "Error generating access token")
 
 	var buffer bytes.Buffer
@@ -222,7 +222,7 @@ func (ts *MFATestSuite) TestMFAVerifyFactor() {
 			secondarySession.FactorID = &f.ID
 			require.NoError(ts.T(), ts.API.db.Create(secondarySession), "Error saving test session")
 
-			token, err := generateAccessToken(ts.API.db, user, r.SessionId, &ts.Config.JWT)
+			token, _, err := generateAccessToken(ts.API.db, user, r.SessionId, &ts.Config.JWT)
 
 			require.NoError(ts.T(), err)
 
@@ -318,7 +318,7 @@ func (ts *MFATestSuite) TestUnenrollVerifiedFactor() {
 
 			var buffer bytes.Buffer
 
-			token, err := generateAccessToken(ts.API.db, u, &s.ID, &ts.Config.JWT)
+			token, _, err := generateAccessToken(ts.API.db, u, &s.ID, &ts.Config.JWT)
 			require.NoError(ts.T(), err)
 
 			w := httptest.NewRecorder()
@@ -360,7 +360,7 @@ func (ts *MFATestSuite) TestUnenrollUnverifiedFactor() {
 
 	var buffer bytes.Buffer
 
-	token, err := generateAccessToken(ts.API.db, u, &s.ID, &ts.Config.JWT)
+	token, _, err := generateAccessToken(ts.API.db, u, &s.ID, &ts.Config.JWT)
 	require.NoError(ts.T(), err)
 	require.NoError(ts.T(), json.NewEncoder(&buffer).Encode(map[string]interface{}{
 		"factor_id": f.ID,
diff --git a/internal/api/phone_test.go b/internal/api/phone_test.go
index ffcb0994..93a7e7d6 100644
--- a/internal/api/phone_test.go
+++ b/internal/api/phone_test.go
@@ -128,7 +128,7 @@ func (ts *PhoneTestSuite) TestMissingSmsProviderConfig() {
 	require.NoError(ts.T(), ts.API.db.Update(u), "Error updating new test user")
 
 	var token string
-	token, err = generateAccessToken(ts.API.db, u, nil, &ts.Config.JWT)
+	token, _, err = generateAccessToken(ts.API.db, u, nil, &ts.Config.JWT)
 	require.NoError(ts.T(), err)
 
 	cases := []struct {
diff --git a/internal/api/user_test.go b/internal/api/user_test.go
index b554316c..2297a128 100644
--- a/internal/api/user_test.go
+++ b/internal/api/user_test.go
@@ -49,7 +49,7 @@ func (ts *UserTestSuite) TestUserGet() {
 	u, err := models.FindUserByEmailAndAudience(ts.API.db, "test@example.com", ts.Config.JWT.Aud)
 	require.NoError(ts.T(), err, "Error finding user")
 	var token string
-	token, err = generateAccessToken(ts.API.db, u, nil, &ts.Config.JWT)
+	token, _, err = generateAccessToken(ts.API.db, u, nil, &ts.Config.JWT)
 
 	require.NoError(ts.T(), err, "Error generating access token")
 
@@ -115,7 +115,7 @@ func (ts *UserTestSuite) TestUserUpdateEmail() {
 			require.NoError(ts.T(), ts.API.db.Create(u), "Error saving test user")
 
 			var token string
-			token, err = generateAccessToken(ts.API.db, u, nil, &ts.Config.JWT)
+			token, _, err = generateAccessToken(ts.API.db, u, nil, &ts.Config.JWT)
 
 			require.NoError(ts.T(), err, "Error generating access token")
 
@@ -179,7 +179,7 @@ func (ts *UserTestSuite) TestUserUpdatePhoneAutoconfirmEnabled() {
 	for _, c := range cases {
 		ts.Run(c.desc, func() {
 			var token string
-			token, err = generateAccessToken(ts.API.db, u, nil, &ts.Config.JWT)
+			token, _, err = generateAccessToken(ts.API.db, u, nil, &ts.Config.JWT)
 			require.NoError(ts.T(), err, "Error generating access token")
 
 			var buffer bytes.Buffer
@@ -293,7 +293,7 @@ func (ts *UserTestSuite) TestUserUpdatePassword() {
 
 			var token string
 
-			token, err = generateAccessToken(ts.API.db, u, c.sessionId, &ts.Config.JWT)
+			token, _, err = generateAccessToken(ts.API.db, u, c.sessionId, &ts.Config.JWT)
 			require.NoError(ts.T(), err)
 			req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token))
 
@@ -323,7 +323,7 @@ func (ts *UserTestSuite) TestUserUpdatePasswordReauthentication() {
 	require.NoError(ts.T(), ts.API.db.Update(u), "Error updating new test user")
 
 	var token string
-	token, err = generateAccessToken(ts.API.db, u, nil, &ts.Config.JWT)
+	token, _, err = generateAccessToken(ts.API.db, u, nil, &ts.Config.JWT)
 	require.NoError(ts.T(), err)
 
 	// request for reauthentication nonce
diff --git a/internal/api/verify_test.go b/internal/api/verify_test.go
index c50c97b5..81c38789 100644
--- a/internal/api/verify_test.go
+++ b/internal/api/verify_test.go
@@ -178,7 +178,7 @@ func (ts *VerifyTestSuite) TestVerifySecureEmailChange() {
 
 		// Generate access token for request
 		var token string
-		token, err = generateAccessToken(ts.API.db, u, nil, &ts.Config.JWT)
+		token, _, err = generateAccessToken(ts.API.db, u, nil, &ts.Config.JWT)
 		require.NoError(ts.T(), err)
 		req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token))