···19192020```bash
2121xcaddy build \
2222- --with github.com/vvill/caddy-atproto-auth
2222+ --with tangled.org/vvill.dev/caddy-atproto-auth
2323```
24242525-### Example: Centralized Auth Hub
2525+## Configuration
2626+2727+### Global Options
2828+2929+The `atproto` global block configures the shared storage and security settings.
26302731```caddyfile
2832{
2933 atproto {
3434+ # Path to the SQLite database.
3535+ # Default: "atproto.db"
3036 storage_path /var/lib/caddy/atproto.db
3131- cookie_secret "your-very-long-random-secret-key"
3737+3838+ # A random 32+ character string used to sign session cookies.
3939+ # REQUIRED.
4040+ cookie_secret "change-me-to-a-secure-random-string-at-least-32-chars"
3241 }
3342}
4343+```
34443535-# The Portal (Login page and OAuth endpoints)
4545+### Authentication Portal (`atproto_portal`)
4646+4747+The `atproto_portal` directive configures the central authentication server. This handles the OAuth flow, serves the login page, and issues session cookies.
4848+4949+```caddyfile
3650auth.example.com {
3751 atproto_portal {
3838- name "My HomeLab"
5252+ # The public domain of the portal.
5353+ # REQUIRED.
3954 domain auth.example.com
5555+5656+ # The display name shown on the login page.
5757+ # Default: "Authentication Portal"
5858+ name "My Services"
5959+6060+ # Custom UI templates (optional)
6161+ ui {
6262+ # Path to a custom HTML template for the login page.
6363+ login_template /path/to/login.html
6464+ }
4065 }
4166}
6767+```
42684343-# A protected application
6969+### Authentication Gate (`atproto_gate`)
7070+7171+The `atproto_gate` directive protects your services. It verifies the session cookie and enforces access control.
7272+7373+```caddyfile
4474app.example.com {
4575 atproto_gate {
7676+ # List of allowed identities (DIDs or Handles).
7777+ # REQUIRED.
4678 allow @alice.bsky.social
4747- allow did:plc:1234...
7979+ allow did:plc:1234abcd...
8080+8181+ # URL of the central Auth Portal.
8282+ # Requests without a valid session will be redirected here.
8383+ # REQUIRED (unless in Standalone Mode).
4884 portal_url https://auth.example.com
8585+8686+ # Standalone Mode Configuration (Alternative to portal_url)
8787+ # If set, this gate acts as its own portal.
8888+ # domain app.example.com
8989+9090+ # Custom UI templates (optional)
9191+ ui {
9292+ # Path to a custom HTML template for the "Access Denied" page.
9393+ forbidden_template /path/to/forbidden.html
9494+ }
4995 }
5050-9696+5197 reverse_proxy localhost:8080
5298}
5399```
5410055101## Documentation
561025757-See the `docs/` folder for detailed architectural constraints and configuration options.
103103+See the `docs/` folder for detailed architectural constraints and implementation details.
···88 "github.com/caddyserver/caddy/v2/caddyconfig/caddyfile"
99 "github.com/caddyserver/caddy/v2/caddyconfig/httpcaddyfile"
10101111- "github.com/vvill/caddy-atproto-auth/internal/db"
1212- "github.com/vvill/caddy-atproto-auth/internal/oauth"
1111+ "tangled.org/vvill.dev/caddy-atproto-auth/internal/db"
1212+ "tangled.org/vvill.dev/caddy-atproto-auth/internal/oauth"
1313)
14141515func init() {
···3939func (a *App) Provision(ctx caddy.Context) error {
4040 // Defaults
4141 if a.StoragePath == "" {
4242- a.StoragePath = "atproto.db" // Relative to workdir or specific path
4242+ a.StoragePath = "atproto.db"
4343 }
4444- // Resolve relative path against Caddy's storage or workdir if needed.
4545- // For simplicity, we assume absolute or relative to CWD.
46444745 // Initialize DB
4846 store, err := db.NewStore(a.StoragePath)
···5048 return fmt.Errorf("failed to initialize atproto storage: %w", err)
5149 }
5250 a.Store = store
5353-5454- // Initialize OAuth Manager (requires client ID and callback URL to be fully configured,
5555- // but those might be per-portal or global. The spec says "acts as an OAuth Client".
5656- // If the plugin acts as a *single* client for many subdomains, we need global config for client ID.
5757- // But spec says: "Path A: The Self-Contained Route" and "Path B: The Auth Hub".
5858- // This implies potentially different client IDs for different sites OR one central hub.
5959- // For now, let's defer OAuthManager creation to the Portal or Gate if it's per-route,
6060- // OR we need to add ClientID/CallbackURL to the global config if it's shared.
6161- //
6262- // Looking at the spec:
6363- // "The module acts as an OAuth Client"
6464- // "Global Configuration: storage_path, cookie_secret"
6565- //
6666- // It seems the App module holds the *Storage* and *Keys*.
6767- // The *Portal* (or Gate) defines the "Client" identity (metadata, callback).
6868- // However, `oauth.NewManager` takes a `db.Store`. So the App owns the Store.
6969- // The Portal will instantiate the Manager using the App's Store.
70517152 return nil
7253}