Skip to content

Commit 980b370

Browse files
committed
chore: scope down key generation to validate method
1 parent 7e68a15 commit 980b370

File tree

2 files changed

+26
-80
lines changed

2 files changed

+26
-80
lines changed

pkg/config/apikeys.go

Lines changed: 21 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -6,108 +6,63 @@ import (
66
"crypto/elliptic"
77
"crypto/rsa"
88
"encoding/base64"
9-
"fmt"
109
"io/fs"
1110
"math/big"
12-
"os"
1311
"time"
1412

1513
"github.com/go-errors/errors"
1614
"github.com/golang-jwt/jwt/v5"
1715
"github.com/google/uuid"
18-
"github.com/supabase/cli/pkg/fetcher"
1916
)
2017

2118
// generateAPIKeys generates JWT tokens using the appropriate signing method
22-
func (c *config) generateAPIKeys(fsys fs.FS) error {
23-
// Load signing keys if path is provided
24-
var signingKeys []JWK
25-
if len(c.Auth.SigningKeysPath) > 0 {
26-
f, err := fsys.Open(c.Auth.SigningKeysPath)
27-
if err != nil {
28-
// Ignore missing signing key path - will fall back to symmetric signing
29-
fmt.Fprintf(os.Stderr, "Warning: Failed to generate asymmetric keys, falling back to symmetric: %v\n", err)
30-
} else {
31-
parsedKeys, _ := fetcher.ParseJSON[[]JWK](f)
32-
signingKeys = parsedKeys
33-
c.Auth.SigningKeys = signingKeys // Store for later use
34-
}
35-
}
36-
19+
func (a *auth) generateAPIKeys(fsys fs.FS) error {
3720
// Generate anon key if not provided
38-
if len(c.Auth.AnonKey.Value) == 0 {
39-
if len(signingKeys) > 0 {
40-
if signed, err := generateAsymmetricJWT(signingKeys[0], "anon"); err != nil {
41-
// Fall back to symmetric signing if asymmetric fails
42-
fmt.Fprintf(os.Stderr, "Warning: Failed to generate asymmetric anon key, falling back to symmetric: %v\n", err)
43-
c.Auth.AnonKey.Value = generateSymmetricJWT(c.Auth.JwtSecret.Value, "anon")
44-
} else {
45-
c.Auth.AnonKey.Value = signed
46-
}
21+
if len(a.AnonKey.Value) == 0 {
22+
if signed, err := a.generateJWT("anon"); err != nil {
23+
return err
4724
} else {
48-
c.Auth.AnonKey.Value = generateSymmetricJWT(c.Auth.JwtSecret.Value, "anon")
25+
a.AnonKey.Value = signed
4926
}
5027
}
51-
5228
// Generate service_role key if not provided
53-
if len(c.Auth.ServiceRoleKey.Value) == 0 {
54-
if len(signingKeys) > 0 {
55-
if signed, err := generateAsymmetricJWT(signingKeys[0], "service_role"); err != nil {
56-
// Fall back to symmetric signing if asymmetric fails
57-
fmt.Fprintf(os.Stderr, "Warning: Failed to generate asymmetric service_role key, falling back to symmetric: %v\n", err)
58-
c.Auth.ServiceRoleKey.Value = generateSymmetricJWT(c.Auth.JwtSecret.Value, "service_role")
59-
} else {
60-
c.Auth.ServiceRoleKey.Value = signed
61-
}
29+
if len(a.ServiceRoleKey.Value) == 0 {
30+
if signed, err := a.generateJWT("service_role"); err != nil {
31+
return err
6232
} else {
63-
c.Auth.ServiceRoleKey.Value = generateSymmetricJWT(c.Auth.JwtSecret.Value, "service_role")
33+
a.ServiceRoleKey.Value = signed
6434
}
6535
}
66-
6736
return nil
6837
}
6938

70-
// createJWTClaims creates standardized JWT claims for API keys
71-
func createJWTClaims(role string) CustomClaims {
72-
now := time.Now()
73-
return CustomClaims{
74-
Issuer: "supabase-demo",
75-
Role: role,
76-
RegisteredClaims: jwt.RegisteredClaims{
77-
ExpiresAt: jwt.NewNumericDate(now.Add(time.Hour * 24 * 365 * 10)), // 10 years
78-
},
39+
func (a auth) generateJWT(role string) (string, error) {
40+
claims := CustomClaims{Issuer: "supabase-demo", Role: role}
41+
if len(a.SigningKeys) > 0 {
42+
claims.ExpiresAt = jwt.NewNumericDate(time.Now().Add(time.Hour * 24 * 365 * 10)) // 10 years
43+
return generateAsymmetricJWT(a.SigningKeys[0], claims)
7944
}
80-
}
81-
82-
// generateSymmetricJWT generates a JWT using symmetric signing with jwt_secret
83-
func generateSymmetricJWT(jwtSecret, role string) string {
84-
claims := createJWTClaims(role)
85-
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
86-
87-
signed, err := token.SignedString([]byte(jwtSecret))
45+
// Fallback to generating symmetric keys
46+
signed, err := claims.NewToken().SignedString([]byte(a.JwtSecret.Value))
8847
if err != nil {
89-
// This should not happen if JWT secret is valid, but return empty string as fallback
90-
fmt.Fprintf(os.Stderr, "Error: Failed to generate %s key: %v\n", role, err)
91-
return ""
48+
return "", errors.Errorf("failed to generate JWT: %w", err)
9249
}
93-
return signed
50+
return signed, nil
9451
}
9552

9653
// generateAsymmetricJWT generates a JWT token signed with the provided JWK private key
97-
func generateAsymmetricJWT(jwk JWK, role string) (string, error) {
54+
func generateAsymmetricJWT(jwk JWK, claims CustomClaims) (string, error) {
9855
privateKey, err := jwkToPrivateKey(jwk)
9956
if err != nil {
10057
return "", errors.Errorf("failed to convert JWK to private key: %w", err)
10158
}
10259

103-
claims := createJWTClaims(role)
104-
10560
// Determine signing method based on algorithm
10661
var token *jwt.Token
10762
switch jwk.Algorithm {
108-
case "RS256":
63+
case AlgRS256:
10964
token = jwt.NewWithClaims(jwt.SigningMethodRS256, claims)
110-
case "ES256":
65+
case AlgES256:
11166
token = jwt.NewWithClaims(jwt.SigningMethodES256, claims)
11267
default:
11368
return "", errors.Errorf("unsupported algorithm: %s", jwk.Algorithm)

pkg/config/config.go

Lines changed: 5 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -653,19 +653,7 @@ func (c *config) Load(path string, fsys fs.FS) error {
653653
if err := c.resolve(builder, fsys); err != nil {
654654
return err
655655
}
656-
657-
validateErr := c.Validate(fsys)
658-
if validateErr != nil {
659-
return validateErr
660-
}
661-
662-
// Generate API keys (anon/service role keys) after paths are resolved & validated
663-
// as we might need to use user-provided signing keys
664-
if err := c.generateAPIKeys(fsys); err != nil {
665-
return err
666-
}
667-
668-
return nil
656+
return c.Validate(fsys)
669657
}
670658

671659
func VersionCompare(a, b string) int {
@@ -853,9 +841,12 @@ func (c *config) Validate(fsys fs.FS) error {
853841
} else if err != nil {
854842
return errors.Errorf("failed to read signing keys: %w", err)
855843
} else if c.Auth.SigningKeys, err = fetcher.ParseJSON[[]JWK](f); err != nil {
856-
return errors.Errorf("failed to decode signign keys: %w", err)
844+
return errors.Errorf("failed to decode signing keys: %w", err)
857845
}
858846
}
847+
if err := c.Auth.generateAPIKeys(fsys); err != nil {
848+
return err
849+
}
859850
if err := c.Auth.Hook.validate(); err != nil {
860851
return err
861852
}

0 commit comments

Comments
 (0)