A community based topic aggregation platform built on atproto
1package oauth 2 3import ( 4 "crypto/rand" 5 "crypto/sha256" 6 "encoding/base64" 7 "fmt" 8) 9 10// PKCE (Proof Key for Code Exchange) - RFC 7636 11// Prevents authorization code interception attacks 12 13// PKCEChallenge contains the code verifier and challenge for PKCE 14type PKCEChallenge struct { 15 Verifier string // Random string (43-128 characters) 16 Challenge string // Base64URL(SHA256(verifier)) 17 Method string // Always "S256" for atProto 18} 19 20// GeneratePKCEChallenge generates a new PKCE code verifier and challenge 21// Uses S256 method (SHA-256 hash) as required by atProto OAuth 22func GeneratePKCEChallenge() (*PKCEChallenge, error) { 23 // Generate 32 random bytes (will be 43 chars when base64url encoded) 24 verifierBytes := make([]byte, 32) 25 if _, err := rand.Read(verifierBytes); err != nil { 26 return nil, fmt.Errorf("failed to generate random bytes: %w", err) 27 } 28 29 // Base64URL encode (no padding) 30 verifier := base64.RawURLEncoding.EncodeToString(verifierBytes) 31 32 // Create SHA-256 hash of verifier 33 hash := sha256.Sum256([]byte(verifier)) 34 challenge := base64.RawURLEncoding.EncodeToString(hash[:]) 35 36 return &PKCEChallenge{ 37 Verifier: verifier, 38 Challenge: challenge, 39 Method: "S256", 40 }, nil 41} 42 43// GenerateState generates a random state parameter for CSRF protection 44// State is used to prevent CSRF attacks in the OAuth flow 45func GenerateState() (string, error) { 46 // Generate 32 random bytes 47 stateBytes := make([]byte, 32) 48 if _, err := rand.Read(stateBytes); err != nil { 49 return "", fmt.Errorf("failed to generate random state: %w", err) 50 } 51 52 return base64.RawURLEncoding.EncodeToString(stateBytes), nil 53}