feat(auth): implement OAuth 2.0 authorization code flow and dynamic client registration
- Add OAuth 2.0 support with authorization code flow and dynamic client registration. - Introduce new handlers for OAuth metadata, client registration, authorization, and token issuance. - Enhance authentication middleware to support OAuth client credentials. - Create in-memory stores for authorization codes and tokens. - Update configuration to include OAuth client details. - Ensure validation checks for OAuth clients in the configuration.
This commit is contained in:
74
internal/auth/token_store.go
Normal file
74
internal/auth/token_store.go
Normal file
@@ -0,0 +1,74 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
const defaultTokenTTL = time.Hour
|
||||
|
||||
type tokenEntry struct {
|
||||
keyID string
|
||||
expiresAt time.Time
|
||||
}
|
||||
|
||||
// TokenStore issues and validates short-lived opaque access tokens for OAuth
|
||||
// client credentials flow.
|
||||
type TokenStore struct {
|
||||
mu sync.RWMutex
|
||||
tokens map[string]tokenEntry
|
||||
ttl time.Duration
|
||||
}
|
||||
|
||||
func NewTokenStore(ttl time.Duration) *TokenStore {
|
||||
if ttl <= 0 {
|
||||
ttl = defaultTokenTTL
|
||||
}
|
||||
s := &TokenStore{
|
||||
tokens: make(map[string]tokenEntry),
|
||||
ttl: ttl,
|
||||
}
|
||||
go s.sweepLoop()
|
||||
return s
|
||||
}
|
||||
|
||||
// Issue generates a new token for the given keyID and returns the token and its TTL.
|
||||
func (s *TokenStore) Issue(keyID string) (string, time.Duration, error) {
|
||||
b := make([]byte, 32)
|
||||
if _, err := rand.Read(b); err != nil {
|
||||
return "", 0, err
|
||||
}
|
||||
token := hex.EncodeToString(b)
|
||||
s.mu.Lock()
|
||||
s.tokens[token] = tokenEntry{keyID: keyID, expiresAt: time.Now().Add(s.ttl)}
|
||||
s.mu.Unlock()
|
||||
return token, s.ttl, nil
|
||||
}
|
||||
|
||||
// Lookup validates a token and returns the associated keyID.
|
||||
func (s *TokenStore) Lookup(token string) (string, bool) {
|
||||
s.mu.RLock()
|
||||
entry, ok := s.tokens[token]
|
||||
s.mu.RUnlock()
|
||||
if !ok || time.Now().After(entry.expiresAt) {
|
||||
return "", false
|
||||
}
|
||||
return entry.keyID, true
|
||||
}
|
||||
|
||||
func (s *TokenStore) sweepLoop() {
|
||||
ticker := time.NewTicker(5 * time.Minute)
|
||||
defer ticker.Stop()
|
||||
for range ticker.C {
|
||||
now := time.Now()
|
||||
s.mu.Lock()
|
||||
for token, entry := range s.tokens {
|
||||
if now.After(entry.expiresAt) {
|
||||
delete(s.tokens, token)
|
||||
}
|
||||
}
|
||||
s.mu.Unlock()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user