6b1bd7c812
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
43 lines
1.2 KiB
Go
43 lines
1.2 KiB
Go
package authkit
|
|
|
|
import (
|
|
"crypto/sha256"
|
|
"crypto/subtle"
|
|
"encoding/hex"
|
|
"net/http"
|
|
"strings"
|
|
)
|
|
|
|
// ExtractAPIKey pulls the API key from r.
|
|
// Checks X-API-Key first, then "Authorization: Bearer <k>".
|
|
// Returns "" if neither is present.
|
|
func ExtractAPIKey(r *http.Request) string {
|
|
if v := strings.TrimSpace(r.Header.Get("X-API-Key")); v != "" {
|
|
return v
|
|
}
|
|
auth := strings.TrimSpace(r.Header.Get("Authorization"))
|
|
if strings.HasPrefix(auth, "Bearer ") {
|
|
return strings.TrimSpace(auth[len("Bearer "):])
|
|
}
|
|
return ""
|
|
}
|
|
|
|
// ConstantTimeEqualString compares a and b in constant time.
|
|
func ConstantTimeEqualString(a, b string) bool {
|
|
if len(a) != len(b) {
|
|
return false
|
|
}
|
|
return subtle.ConstantTimeCompare([]byte(a), []byte(b)) == 1
|
|
}
|
|
|
|
// ConstantTimeEqualHashedKey hashes candidatePlain with sha256 and compares
|
|
// against storedHashHex in constant time. Returns false on bad hex; never panics.
|
|
func ConstantTimeEqualHashedKey(candidatePlain, storedHashHex string) bool {
|
|
stored, err := hex.DecodeString(storedHashHex)
|
|
if err != nil || len(stored) != sha256.Size {
|
|
return false
|
|
}
|
|
sum := sha256.Sum256([]byte(candidatePlain))
|
|
return subtle.ConstantTimeCompare(sum[:], stored) == 1
|
|
}
|