@@ -13,23 +13,23 @@ import (
1313 "syscall"
1414 "time"
1515
16- "github.com/aricart/callout.go"
1716 "github.com/go-playground/validator/v10"
1817 "github.com/golang-jwt/jwt/v5"
1918 "github.com/joho/godotenv"
2019 natsjwt "github.com/nats-io/jwt/v2"
2120 nslogger "github.com/nats-io/nats-server/v2/logger"
2221 "github.com/nats-io/nats.go"
2322 "github.com/nats-io/nkeys"
23+ "github.com/synadia-io/callout.go"
2424)
2525
2626type Config struct {
2727 VERIFY_URL string `validate:"omitempty,url"`
28- CALLOUT_ACCOUNT_NKEY_FILE string `validate:"required,filepath"`
28+ CALLOUT_ACCOUNT_PUBLIC_KEY_FILE string `validate:"required,filepath"`
2929 CALLOUT_ACCOUNT_SIGNING_KEY_FILE string `validate:"required,filepath"`
3030 CALLOUT_ACCOUNT_XKEY_FILE string `validate:"required,filepath"`
3131 CALLOUT_USER_CREDS_FILE string `validate:"required,filepath"`
32- APP_ACCOUNT_NKEY_FILE string `validate:"required,filepath"`
32+ APP_ACCOUNT_PUBLIC_KEY_FILE string `validate:"required,filepath"`
3333 APP_ACCOUNT_SIGNING_KEY_FILE string `validate:"required,filepath"`
3434 SERVER_URL string `validate:"required,url"`
3535 TOKEN_EXPIRATION_TIME_S int `validate:"required"`
@@ -48,11 +48,11 @@ func main() {
4848
4949 cfg := Config {
5050 VERIFY_URL : os .Getenv ("VERIFY_URL" ),
51- CALLOUT_ACCOUNT_NKEY_FILE : os .Getenv ("CALLOUT_ACCOUNT_NKEY_FILE " ),
51+ CALLOUT_ACCOUNT_PUBLIC_KEY_FILE : os .Getenv ("CALLOUT_ACCOUNT_PUBLIC_KEY_FILE " ),
5252 CALLOUT_ACCOUNT_SIGNING_KEY_FILE : os .Getenv ("CALLOUT_ACCOUNT_SIGNING_KEY_FILE" ),
5353 CALLOUT_ACCOUNT_XKEY_FILE : os .Getenv ("CALLOUT_ACCOUNT_XKEY_FILE" ),
5454 CALLOUT_USER_CREDS_FILE : os .Getenv ("CALLOUT_USER_CREDS_FILE" ),
55- APP_ACCOUNT_NKEY_FILE : os .Getenv ("APP_ACCOUNT_NKEY_FILE " ),
55+ APP_ACCOUNT_PUBLIC_KEY_FILE : os .Getenv ("APP_ACCOUNT_PUBLIC_KEY_FILE " ),
5656 APP_ACCOUNT_SIGNING_KEY_FILE : os .Getenv ("APP_ACCOUNT_SIGNING_KEY_FILE" ),
5757 SERVER_URL : os .Getenv ("SERVER_URL" ),
5858 TOKEN_EXPIRATION_TIME_S : func () int {
@@ -75,42 +75,38 @@ func main() {
7575 logger .Noticef ("config validated" )
7676
7777 // Keys description:
78- // calloutAccountKP: signs callout responses.
79- // should be **account key** of the callout account
78+ // calloutAccountPublicKey: issuer for callout responses.
79+ // should be **public key** of the callout account
80+ // calloutAccountSigningKeyKP: signs callout responses.
81+ // should be **signing key** of the callout account
8082 // calloutEncryptionKP: encrypts callout responses.
8183 // should be **encryption key** of the callout account
82- // appAccountKP: key pair for assigning account to the user
83- // should be **account key** of the app account
84+ // appAccountPublicKey: account assignment for the user
85+ // should be **public key** of the app account
8486 // appAccountSigningKeyKP: key pair for signing the user
8587 // should be **signing key** of the app account
86- calloutAccountKP , err := loadAndParseKeys (cfg .CALLOUT_ACCOUNT_NKEY_FILE )
88+ calloutAccountSigningKeyKP , err := loadAndParseKeys (cfg .CALLOUT_ACCOUNT_SIGNING_KEY_FILE )
8789 if err != nil {
88- panic (fmt .Errorf ("error creating issuer key pair: %v" , err ))
90+ panic (fmt .Errorf ("error creating signing key pair: %v" , err ))
8991 }
90-
91- // TODO: determine how avoid using calloutAccountKP
92- // calloutAccountSigningKeyKP, err := loadAndParseKeys(cfg.CALLOUT_ACCOUNT_SIGNING_KEY_FILE)
93- // if err != nil {
94- // panic(fmt.Errorf("error creating signing key pair: %v", err))
95- // }
9692 calloutEncryptionKP , err := loadAndParseKeys (cfg .CALLOUT_ACCOUNT_XKEY_FILE )
9793 if err != nil {
9894 panic (fmt .Errorf ("error creating encryption key pair: %v" , err ))
9995 }
100- appAccountKP , err := loadAndParseKeys (cfg .APP_ACCOUNT_NKEY_FILE )
101- if err != nil {
102- panic (fmt .Errorf ("error creating account key pair: %v" , err ))
103- }
10496 appAccountSigningKeyKP , err := loadAndParseKeys (cfg .APP_ACCOUNT_SIGNING_KEY_FILE )
10597 if err != nil {
10698 panic (fmt .Errorf ("error creating account signing key pair: %v" , err ))
10799 }
108100
109101 logger .Noticef ("keys loaded" )
110102
111- appAccountPublicKey , err := appAccountKP .PublicKey ()
103+ calloutAccountPublicKey , err := loadPublicAccountKey (cfg .CALLOUT_ACCOUNT_PUBLIC_KEY_FILE )
104+ if err != nil {
105+ panic (fmt .Errorf ("error loading callout account public key: %v" , err ))
106+ }
107+ appAccountPublicKey , err := loadPublicAccountKey (cfg .APP_ACCOUNT_PUBLIC_KEY_FILE )
112108 if err != nil {
113- panic (fmt .Errorf ("error getting app account public key: %v" , err ))
109+ panic (fmt .Errorf ("error loading app account public key: %v" , err ))
114110 }
115111
116112 // Function that creates the users
@@ -183,7 +179,9 @@ func main() {
183179 _ , err = callout .NewAuthorizationService (nc ,
184180 callout .Authorizer (authorizer ),
185181 // Sign the response with the callout account's signing key
186- callout .ResponseSignerKey (calloutAccountKP ),
182+ callout .ResponseSignerKey (calloutAccountSigningKeyKP ),
183+ // Let NATS verify the signing key against the callout account
184+ callout .ResponseSignerIssuer (calloutAccountPublicKey ),
187185 // Encrypt the response with the callout account's encryption key
188186 callout .EncryptionKey (calloutEncryptionKP ))
189187
@@ -198,23 +196,23 @@ func main() {
198196}
199197
200198func VerifyTokenLocally (token string , secretKeys []string , algorithm string ) (* jwt.Token , error ) {
201- var lastErr error
202-
203- for _ , secretKey := range secretKeys {
204- parsedToken , err := jwt .Parse (token , func (pToken * jwt.Token ) (interface {}, error ) {
205- if pToken .Method .Alg () != algorithm {
206- return nil , fmt .Errorf ("unexpected signing method: %v" , pToken .Header ["alg" ])
207- }
208- return []byte (secretKey ), nil
209- })
210-
211- if err == nil && parsedToken .Valid {
212- return parsedToken , nil
213- }
214- lastErr = err
215- }
216-
217- return nil , fmt .Errorf ("failed to verify token with any key: %v" , lastErr )
199+ var lastErr error
200+
201+ for _ , secretKey := range secretKeys {
202+ parsedToken , err := jwt .Parse (token , func (pToken * jwt.Token ) (interface {}, error ) {
203+ if pToken .Method .Alg () != algorithm {
204+ return nil , fmt .Errorf ("unexpected signing method: %v" , pToken .Header ["alg" ])
205+ }
206+ return []byte (secretKey ), nil
207+ })
208+
209+ if err == nil && parsedToken .Valid {
210+ return parsedToken , nil
211+ }
212+ lastErr = err
213+ }
214+
215+ return nil , fmt .Errorf ("failed to verify token with any key: %v" , lastErr )
218216}
219217
220218func VerifyToken (token string , verificationUrl string ) error {
@@ -239,6 +237,24 @@ func VerifyToken(token string, verificationUrl string) error {
239237 return nil
240238}
241239
240+ func loadPublicAccountKey (fp string ) (string , error ) {
241+ if fp == "" {
242+ return "" , errors .New ("public key file required" )
243+ }
244+ data , err := os .ReadFile (fp )
245+ if err != nil {
246+ return "" , fmt .Errorf ("error reading public key file: %w" , err )
247+ }
248+ key := strings .TrimSpace (string (data ))
249+ if key == "" {
250+ return "" , errors .New ("public key file is empty" )
251+ }
252+ if ! nkeys .IsValidPublicAccountKey (key ) {
253+ return "" , errors .New ("public key must be an account public key" )
254+ }
255+ return key , nil
256+ }
257+
242258func loadAndParseKeys (fp string ) (nkeys.KeyPair , error ) {
243259 if fp == "" {
244260 return nil , errors .New ("key file required" )
0 commit comments