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