Wahoo provides password, opaque-token, session, and CSRF primitives. Generated account routes return `501 Not Implemented` until the application supplies storage, mail, cookies, authorization, and rate limits.

> **Work in progress:** Do not use Wahoo in production yet.

## Provided API

| API | Use it to |
| --- | --- |
| `auth.HashPassword` | Create a bcrypt hash after a 12-character minimum check. |
| `auth.VerifyLogin` | Verify credentials with a dummy bcrypt check for absent users. Storage failures are returned. |
| `auth.NewToken` | Create a URL-safe opaque token. |
| `auth.TokenHash` | Hash an opaque token before storage. |
| `auth.AuthenticateSession` | Validate token hash, expiry, and revocation through an application `SessionStore`. |
| `auth.NewCSRFToken` | Create a token for an application-owned CSRF design. |
| `auth.VerifyCSRFToken` | Compare CSRF tokens in constant time. |

Do not store raw passwords, session tokens, reset tokens, or CSRF tokens.

## Session Store

Implement only the lookup needed by the framework primitive:

```go
type SessionStore interface {
    FindSessionByTokenHash(context.Context, string) (*auth.Session, error)
}
```

```go
rawToken, err := auth.NewToken(32)
if err != nil {
    return err
}
hash, err := auth.TokenHash(rawToken)
// Store hash, user ID, expiry, and revocation time.

session, err := auth.AuthenticateSession(r.Context(), sessions, rawToken, time.Now())
```

The application must create, rotate, revoke, and persist sessions. It must set a secure, `HttpOnly`, `SameSite` cookie. Use `Secure: false` only for local HTTP development.

## Login And Reset

A login handler must normalize email, rate limit attempts, return the same credential failure for absent and incorrect users, create a new session, write an audit event, and set a secure cookie.

A password-reset flow must always return the same public response, store only a single-use token hash, use a short expiry, revoke sessions after a successful reset, and write an audit event.

## CSRF

Use a server-side synchronizer token or signed double-submit token for browser mutations. Also validate `Origin` or `Referer`. CORS does not prevent CSRF.

## OAuth And MFA

Keep OAuth and MFA behind application provider interfaces. OAuth requires state, nonce, and PKCE. Use WebAuthn or TOTP for MFA, hash recovery codes, and require short-lived step-up state for sensitive actions.