package auth import ( "crypto/rand" "crypto/sha256" "encoding/base64" "fmt" ) // SessionDuration controls how long a login stays valid without activity. // TouchSession bumps last_seen_at on each authenticated request, but // expires_at (set at login) is what actually gates access. const SessionDuration = 30 * 24 * 60 * 60 // 30 days, in seconds // tokenLen is deliberately large: this is the only secret standing between // an attacker and a full account take-over, so it gets more entropy than a // password would need. const tokenLen = 32 // NewSessionToken returns a random token to hand to the client, and the hash // of it to store in the database. Only the hash is ever persisted, so a // leaked database dump doesn't also leak usable session tokens. func NewSessionToken() (token string, hash []byte, err error) { raw := make([]byte, tokenLen) if _, err := rand.Read(raw); err != nil { return "", nil, fmt.Errorf("generate token: %w", err) } token = base64.RawURLEncoding.EncodeToString(raw) return token, HashSessionToken(token), nil } // HashSessionToken hashes a token presented by a client so it can be looked // up against the stored hash. func HashSessionToken(token string) []byte { sum := sha256.Sum256([]byte(token)) return sum[:] }