A small library providing go HTTP handlers for OIDC authentication and API key validation.
- Go 100%
| pkg | ||
| .gitignore | ||
| .golangci.yml | ||
| .goreleaser.yaml | ||
| auth.go | ||
| callback.go | ||
| errs.go | ||
| go.mod | ||
| go.sum | ||
| handlers.go | ||
| info.go | ||
| LICENSE | ||
| login.go | ||
| logout.go | ||
| middleware.go | ||
| oicd.go | ||
| options.go | ||
| README.md | ||
simple-auth
A lightweight Go library providing HTTP handlers for OIDC authentication and API key validation.
Features
- OIDC/OAuth 2.0 authentication with automatic token refresh
- PKCE support for enhanced security
- API key authentication with BLAKE2b hashing
- Cookie-based session management with encryption
- JWT profile authentication support
- Pluggable user storage via interface
Installation
go get git.crawford.zone/jd/simple-auth.git
Quick Start
OIDC Authentication
// Define a User type
type MyUser struct{}
func (u *MyUser) Authorized(path string) bool { return true }
func (u *MyUser) NeedsUpdate(claims *oidc.IDTokenClaims) bool {
return false
}
// Define a UserHandler
type MyUserHandler struct{}
func (h *MyUserHandler) CreateUser(ctx context.Context, claims *oidc.IDTokenClaims) (string, error) {
return "", nil
}
func (h *MyUserHandler) GetUserID(ctx context.Context, subject string) (string, error) {
return "", simpleauth.ErrNoUser
}
func (h *MyUserHandler) GetUser(ctx context.Context, id string) (*MyUser, error) {
return &MyUser{}, nil
}
func (h *MyUserHandler) UpdateUser(ctx context.Context, id string, claims *oidc.IDTokenClaims) (*MyUser, error) {
return &MyUser{}, nil
}
// Create Auth instance
auth, err := simpleauth.New[string, *MyUser](
context.Background(),
&MyUserHandler{},
simpleauth.WithOAuthClient("client-id", "client-secret", "https://app.com/auth/callback"),
simpleauth.WithIssuer("https://issuer.com"),
simpleauth.WithSecurityKeys(hashKey, encryptionKey),
simpleauth.WithPaths(
simpleauth.WithHomePath("/"),
simpleauth.WithLoginPath("/login"),
simpleauth.WithLogoutPath("/logout"),
simpleauth.WithRedirectPath("/auth/callback"),
),
)
// Register handlers
mux := http.NewServeMux()
mux.HandleFunc("/auth/login", auth.LoginHandler())
mux.HandleFunc("/auth/logout", auth.LogoutHandler())
mux.HandleFunc("/auth/callback", auth.CallbackHandler())
mux.Handle("/", auth.InfoHandler(auth.RequireAuthorizedHandler(handler)))
API Key Authentication
// Define KeyHandler
type MyKeyHandler struct{}
func (h *MyKeyHandler) HashKey(key string) string {
sum := blake2b.Sum256([]byte(key))
return base64.RawURLEncoding.EncodeToString(sum[:])
}
func (h *MyKeyHandler) Valid(ctx context.Context, hashedKey string) (bool, error) {
return true, nil
}
// Create ApiAuth instance
apiAuth := simpleauth.NewApi(&MyKeyHandler{}, slog.Default())
// Register middleware
mux := http.NewServeMux()
mux.HandleFunc("/api/data", apiAuth.InfoHandler(handler))
mux.HandleFunc("/api/private", apiAuth.InfoHandler(apiAuth.APIRequireAuthorizedHandler(handler)))
Configuration
Auth Options
| Option | Description |
|---|---|
WithOAuthClient |
Client ID, secret, and redirect URL |
WithSecurityKeys |
Hash key (32/64 bytes) and encryption key (16/24/32 bytes) |
WithJWKSKey |
JWT signing key path and key ID |
WithRedirectURL |
OAuth redirect URL |
WithInsecureHost |
Allow HTTP cookies |
WithInsecureProvider |
Skip TLS verification for OIDC provider |
WithClientID |
OAuth client ID |
WithClientSecret |
OAuth client secret |
WithPkce |
Enable PKCE flow |
WithIssuer |
OIDC issuer URL |
WithResponseMode |
OAuth response mode |
WithScopes |
OAuth scopes (default: openid, email, profile) |
WithCookiePrefix |
Cookie prefix (default: auth) |
WithPaths |
Path configuration |
Paths
| Field | Description | Default |
|---|---|---|
| Home | Post-login redirect | / |
| Login | Login handler | /auth/login |
| Logout | Logout handler | /auth/logout |
| Redirect | OAuth callback | /auth/callback |
| Unauthorized | Unauthorized redirect | - |
Middleware
InfoHandler
Extracts authentication info and adds it to the request context. Must be used before RequireAuthorizedHandler.
mux.Handle("/protected", auth.InfoHandler(handler))
RequireAuthorizedHandler
For web pages - redirects to login/unauthorized pages when not authenticated/authorized.
mux.Handle("/dashboard", auth.InfoHandler(auth.RequireAuthorizedHandler(handler)))
APIRequireAuthorizedHandler
For API endpoints - returns HTTP 401/403 with WWW-Authenticate header instead of redirects.
mux.Handle("/api/data", auth.InfoHandler(auth.APIRequireAuthorizedHandler(handler)))
Accessing User Information
func handler(w http.ResponseWriter, r *http.Request) {
info := auth.GetInfo(r)
if !info.Authenticated {
http.Redirect(w, r, "/auth/login", http.StatusFound)
return
}
// info.ID - User ID
// info.Name - Display name
// info.Picture - Profile URL
// info.Authorized - Path authorization status
}
Accessing API Key Information
func handler(w http.ResponseWriter, r *http.Request) {
info := apiAuth.GetInfo(r)
if !info.Authenticated {
w.Header().Set("WWW-Authenticate", `Bearer realm="Restricted"`)
http.Error(w, "Unauthorized", http.StatusUnauthorized)
return
}
// info.HashedKey - BLAKE2b-hashed API key
}