50 lines
1.3 KiB
Go
50 lines
1.3 KiB
Go
|
|
package auth
|
||
|
|
|
||
|
|
import (
|
||
|
|
"crypto/sha256"
|
||
|
|
"encoding/base64"
|
||
|
|
"strings"
|
||
|
|
)
|
||
|
|
|
||
|
|
// PKCEMethod represents the code challenge method
|
||
|
|
type PKCEMethod string
|
||
|
|
|
||
|
|
const (
|
||
|
|
// PKCEMethodPlain uses the verifier directly as the challenge
|
||
|
|
PKCEMethodPlain PKCEMethod = "plain"
|
||
|
|
// PKCEMethodS256 uses SHA256 hash of the verifier
|
||
|
|
PKCEMethodS256 PKCEMethod = "S256"
|
||
|
|
)
|
||
|
|
|
||
|
|
// VerifyPKCE verifies that the code verifier matches the code challenge
|
||
|
|
func VerifyPKCE(verifier, challenge string, method PKCEMethod) bool {
|
||
|
|
if verifier == "" || challenge == "" {
|
||
|
|
return false
|
||
|
|
}
|
||
|
|
|
||
|
|
switch method {
|
||
|
|
case PKCEMethodPlain, "":
|
||
|
|
// Plain method or no method specified - direct comparison
|
||
|
|
return verifier == challenge
|
||
|
|
case PKCEMethodS256:
|
||
|
|
// S256 method - SHA256 hash, base64url encoded
|
||
|
|
computed := ComputeS256Challenge(verifier)
|
||
|
|
return computed == challenge
|
||
|
|
default:
|
||
|
|
return false
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// ComputeS256Challenge computes the S256 code challenge from a verifier
|
||
|
|
func ComputeS256Challenge(verifier string) string {
|
||
|
|
hash := sha256.Sum256([]byte(verifier))
|
||
|
|
return base64URLEncode(hash[:])
|
||
|
|
}
|
||
|
|
|
||
|
|
// base64URLEncode encodes bytes to base64url without padding
|
||
|
|
func base64URLEncode(data []byte) string {
|
||
|
|
encoded := base64.URLEncoding.EncodeToString(data)
|
||
|
|
// Remove padding
|
||
|
|
return strings.TrimRight(encoded, "=")
|
||
|
|
}
|