A community based topic aggregation platform built on atproto
1package main
2
3import (
4 "crypto/ecdsa"
5 "crypto/elliptic"
6 "crypto/rand"
7 "encoding/json"
8 "fmt"
9 "log"
10 "os"
11
12 "github.com/lestrrat-go/jwx/v2/jwk"
13)
14
15// genjwks generates an ES256 keypair for OAuth client authentication
16// The private key is stored in the config/env, public key is served at /oauth/jwks.json
17//
18// Usage:
19//
20// go run cmd/genjwks/main.go
21//
22// This will output a JSON private key that should be stored in OAUTH_PRIVATE_JWK
23func main() {
24 fmt.Println("Generating ES256 keypair for OAuth client authentication...")
25
26 // Generate ES256 (NIST P-256) private key
27 privateKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
28 if err != nil {
29 log.Fatalf("Failed to generate private key: %v", err)
30 }
31
32 // Convert to JWK
33 jwkKey, err := jwk.FromRaw(privateKey)
34 if err != nil {
35 log.Fatalf("Failed to create JWK from private key: %v", err)
36 }
37
38 // Set key parameters
39 if err = jwkKey.Set(jwk.KeyIDKey, "oauth-client-key"); err != nil {
40 log.Fatalf("Failed to set kid: %v", err)
41 }
42 if err = jwkKey.Set(jwk.AlgorithmKey, "ES256"); err != nil {
43 log.Fatalf("Failed to set alg: %v", err)
44 }
45 if err = jwkKey.Set(jwk.KeyUsageKey, "sig"); err != nil {
46 log.Fatalf("Failed to set use: %v", err)
47 }
48
49 // Marshal to JSON
50 jsonData, err := json.MarshalIndent(jwkKey, "", " ")
51 if err != nil {
52 log.Fatalf("Failed to marshal JWK: %v", err)
53 }
54
55 // Output instructions
56 fmt.Println("\n✅ ES256 keypair generated successfully!")
57 fmt.Println("\n📝 Add this to your .env.dev file:")
58 fmt.Println("\nOAUTH_PRIVATE_JWK='" + string(jsonData) + "'")
59 fmt.Println("\n⚠️ IMPORTANT:")
60 fmt.Println(" - Keep this private key SECRET")
61 fmt.Println(" - Never commit it to version control")
62 fmt.Println(" - Generate a new key for production")
63 fmt.Println(" - The public key will be automatically derived and served at /oauth/jwks.json")
64
65 // Optionally write to a file (not committed)
66 if len(os.Args) > 1 && os.Args[1] == "--save" {
67 filename := "oauth-private-key.json"
68 if err := os.WriteFile(filename, jsonData, 0o600); err != nil {
69 log.Fatalf("Failed to write key file: %v", err)
70 }
71 fmt.Printf("\n💾 Private key saved to %s (remember to add to .gitignore!)\n", filename)
72 }
73}