authkit: initial shared auth module

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-18 16:28:33 +02:00
commit 6b1bd7c812
7 changed files with 520 additions and 0 deletions
+42
View File
@@ -0,0 +1,42 @@
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
}