Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
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
5 changes: 5 additions & 0 deletions developer_tools/scripts/jwt_issuer/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ make release-jwt-issuer BUMP=patch # or minor, major
-jwt-out my-token.jwt \
-jwk-out my-jwks.json \
-priv-out my-private.jwk

# Reuse an existing private key (avoids generating a new key each run)
./bin/jwt_issuer \
-priv-in my-private.jwk
```

## Flags
Expand All @@ -49,6 +53,7 @@ make release-jwt-issuer BUMP=patch # or minor, major
| `-kid` | `test-key-1` | Key ID in JWKS |
| `-jwt-out` | `token.jwt` | Output file for the signed JWT |
| `-jwk-out` | `jwks.json` | Output file for the JWKS |
| `-priv-in` | (none) | Input file for an existing private JWK (reuse key) |
| `-priv-out` | (none) | Output file for the private JWK |

## Example apigw config
Expand Down
33 changes: 24 additions & 9 deletions developer_tools/scripts/jwt_issuer/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ func main() {
jwtFile := flag.String("jwt-out", "token.jwt", "output file for the signed JWT")
jwkFile := flag.String("jwk-out", "jwks.json", "output file for the JWKS (public keys)")
privFile := flag.String("priv-out", "", "output file for the private JWK (optional)")
privInFile := flag.String("priv-in", "", "input file for an existing private JWK (optional, generates new key if not set)")

Comment on lines 29 to 33

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 373ce75 — added a guard that checks all output paths against -priv-in before proceeding.

flag.Parse()

Expand All @@ -41,17 +42,31 @@ func main() {
*email = *subject
}

// Generate ECDSA P-256 key pair
rawKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
if err != nil {
fatal("generate key: %v", err)
}
var privJWK jwk.Key

// Build private JWK
privJWK, err := jwk.Import(rawKey)
if err != nil {
fatal("import private key: %v", err)
if *privInFile != "" {
// Load existing private key from file
privJSON, err := os.ReadFile(*privInFile)
if err != nil {
fatal("read private key file: %v", err)
}
privJWK, err = jwk.ParseKey(privJSON)
if err != nil {
fatal("parse private key: %v", err)
}
fmt.Printf("Private key loaded from %s\n", *privInFile)
Comment on lines +62 to +74

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This feedback makes sense!

Comment on lines +62 to +74

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 373ce75 — after parsing, we now export to ecdsa.PrivateKey and verify the curve is P-256. This catches public-only keys, wrong kty, and wrong curves immediately.

} else {
// Generate ECDSA P-256 key pair
rawKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
if err != nil {
fatal("generate key: %v", err)
}
privJWK, err = jwk.Import(rawKey)
if err != nil {
fatal("import private key: %v", err)
}
}

if err := privJWK.Set(jwk.KeyIDKey, *kid); err != nil {
fatal("set kid: %v", err)
}
Expand Down