@@ -6,108 +6,63 @@ import (
6
6
"crypto/elliptic"
7
7
"crypto/rsa"
8
8
"encoding/base64"
9
- "fmt"
10
9
"io/fs"
11
10
"math/big"
12
- "os"
13
11
"time"
14
12
15
13
"github.com/go-errors/errors"
16
14
"github.com/golang-jwt/jwt/v5"
17
15
"github.com/google/uuid"
18
- "github.com/supabase/cli/pkg/fetcher"
19
16
)
20
17
21
18
// 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 {
37
20
// 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
47
24
} else {
48
- c . Auth . AnonKey .Value = generateSymmetricJWT ( c . Auth . JwtSecret . Value , "anon" )
25
+ a . AnonKey .Value = signed
49
26
}
50
27
}
51
-
52
28
// 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
62
32
} else {
63
- c . Auth . ServiceRoleKey .Value = generateSymmetricJWT ( c . Auth . JwtSecret . Value , "service_role" )
33
+ a . ServiceRoleKey .Value = signed
64
34
}
65
35
}
66
-
67
36
return nil
68
37
}
69
38
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 )
79
44
}
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 ))
88
47
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 )
92
49
}
93
- return signed
50
+ return signed , nil
94
51
}
95
52
96
53
// 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 ) {
98
55
privateKey , err := jwkToPrivateKey (jwk )
99
56
if err != nil {
100
57
return "" , errors .Errorf ("failed to convert JWK to private key: %w" , err )
101
58
}
102
59
103
- claims := createJWTClaims (role )
104
-
105
60
// Determine signing method based on algorithm
106
61
var token * jwt.Token
107
62
switch jwk .Algorithm {
108
- case "RS256" :
63
+ case AlgRS256 :
109
64
token = jwt .NewWithClaims (jwt .SigningMethodRS256 , claims )
110
- case "ES256" :
65
+ case AlgES256 :
111
66
token = jwt .NewWithClaims (jwt .SigningMethodES256 , claims )
112
67
default :
113
68
return "" , errors .Errorf ("unsupported algorithm: %s" , jwk .Algorithm )
0 commit comments