Files
nadir-agent/internal/auth/bearer.go
T
urania 2bf11dda91
build-and-release / release (push) Failing after 17m7s
feat: first release
2026-06-22 16:51:18 +02:00

48 lines
1.5 KiB
Go

package auth
import (
"strings"
"time"
)
// TokenAuth verifies Bearer credentials against the TokenStore and throttles
// brute force. Unlike the login throttle (keyed on username+IP), a Bearer token
// has no "login" step to rate-limit, so guesses are throttled by source IP
// alone. The window is looser than login's because a legitimate dashboard may
// fire many requests in a minute - only repeated *failures* count.
type TokenAuth struct {
store *TokenStore
throttle *failLimiter
}
// NewTokenAuth wraps a store with an IP-keyed failure throttle.
func NewTokenAuth(store *TokenStore) *TokenAuth {
return &TokenAuth{store: store, throttle: newFailLimiter(20, time.Minute)}
}
// Verify resolves a presented Bearer token to its name. throttled is true when
// the source IP is in cooldown after too many bad tokens; the caller should
// answer 429 without consulting the store.
func (a *TokenAuth) Verify(ip, raw string) (name string, ok, throttled bool) {
if a.throttle.blocked(ip) {
return "", false, true
}
name, found := a.store.Lookup(raw)
if !found {
a.throttle.fail(ip)
return "", false, false
}
a.throttle.reset(ip)
return name, true, false
}
// BearerToken extracts the credential from an Authorization header value,
// reporting whether it was a Bearer scheme. Returns ("", false) for cookie-only
// or unauthenticated requests.
func BearerToken(authHeader string) (string, bool) {
if len(authHeader) <= 7 || !strings.EqualFold(authHeader[:7], "Bearer ") {
return "", false
}
return strings.TrimSpace(authHeader[7:]), true
}