AtAuth
TypeScript 90.3%
Rust 9.3%
Dockerfile 0.2%
JavaScript 0.2%
HTML 0.1%
114 1 4

Clone this repository

https://tangled.org/bkb.arcnode.xyz/atauth https://tangled.org/did:plc:k23ujfuppr3hr4pxvtaz7jro/atauth
git@tangled.org:bkb.arcnode.xyz/atauth git@tangled.org:did:plc:k23ujfuppr3hr4pxvtaz7jro/atauth

For self-hosted knots, clone URLs may differ based on your setup.

Download tar.gz
README.md

ATAuth - OIDC Provider for AT Protocol#

An OpenID Connect (OIDC) Provider that uses AT Protocol OAuth (Bluesky) as the identity source. Authenticate users via their @handle -- works with Bluesky or any self-hosted PDS.

What It Does#

ATAuth sits between your apps and AT Protocol identity:

Your App (OIDC Client)
    |
    v
ATAuth (OIDC Provider)
    |
    v
User's PDS (Bluesky / self-hosted)
    |
    v
User authenticates with their AT Proto identity
    |
    v
ATAuth issues standard OIDC tokens back to your app

Any app that supports OpenID Connect can use ATAuth. No custom integration needed.

Screenshots#

Login - Sign in with your AT Protocol identity

Admin Dashboard - Stats and quick actions

Setup Wizard - One-click setup for 20+ self-hosted apps

Access Rules - Per-user control with DID and handle patterns

Features#

  • Standard OIDC Provider: Discovery, authorization, token, userinfo, revocation, JWKS endpoints
  • Passkey Login: WebAuthn/FIDO2 support -- users can register passkeys and skip the Bluesky OAuth flow
  • Forward-Auth SSO Proxy: nginx auth_request based single sign-on for any web service
  • Admin Dashboard: Web UI with setup wizard for 20+ common self-hosted apps
  • Access Control: Per-user DID and handle pattern rules with deny-overrides
  • PKCE Support: Configurable per-client
  • ES256 Signed JWTs: Proper key rotation via JWKS endpoint

Quick Start#

Prerequisites#

  • Docker and Docker Compose
  • A domain with a DNS record pointing to your server (e.g. auth.yourdomain.com)
  • A reverse proxy that terminates TLS (Caddy, Traefik, or nginx)

1. Clone and configure#

git clone https://github.com/Cache8063/atauth.git
cd atauth
cp gateway/.env.example .env

Edit .env -- replace every instance of auth.yourdomain.com with your actual domain:

# These must all use your real domain
OAUTH_CLIENT_ID=https://auth.yourdomain.com/client-metadata.json
OAUTH_REDIRECT_URI=https://auth.yourdomain.com/auth/callback
OIDC_ISSUER=https://auth.yourdomain.com
WEBAUTHN_RP_ID=auth.yourdomain.com
WEBAUTHN_ORIGIN=https://auth.yourdomain.com
CORS_ORIGINS=https://app1.yourdomain.com,https://app2.yourdomain.com

Generate and fill in the three required secrets (run the command once per value):

openssl rand -hex 32
ADMIN_TOKEN=<paste-generated-value>
OIDC_KEY_SECRET=<paste-generated-value>
MFA_ENCRYPTION_KEY=<paste-generated-value>

2. Start the service#

docker compose up -d

The gateway starts on 127.0.0.1:3100. Put a reverse proxy with TLS in front of it. The simplest option is Caddy (automatic HTTPS):

auth.yourdomain.com {
    reverse_proxy localhost:3100
}

See the Homelab Deployment Guide for Traefik and nginx examples.

3. Verify it's running#

curl https://auth.yourdomain.com/.well-known/openid-configuration

You should get a JSON document with all the OIDC endpoints.

4. Register your first app#

Open https://auth.yourdomain.com/admin/login, enter your ADMIN_TOKEN, and use the setup wizard to register an app. The wizard includes presets that auto-fill redirect URIs, scopes, and grant types.

Save the returned client secret -- it is only shown once.

5. Configure your app#

Point your app's OIDC settings to ATAuth's discovery URL:

Setting Value
Discovery URL https://auth.yourdomain.com/.well-known/openid-configuration
Client ID The ID you chose in the wizard
Client Secret The secret returned at registration
Scopes openid profile (add email if needed)

Supported Apps#

The setup wizard includes presets for:

App Auth Method
Audiobookshelf OIDC (OpenID Connect)
Jellyfin OIDC (via SSO plugin)
Gitea / Forgejo OIDC (built-in)
Nextcloud OIDC (via app)
Immich OIDC (built-in)
Grafana OIDC (built-in)
Wiki.js OIDC (built-in)
Portainer OIDC (built-in)
Outline OIDC (built-in)
Mealie OIDC (built-in)
Paperless-ngx OIDC (built-in)
Vaultwarden OIDC (built-in)
Miniflux OIDC (built-in)
Mattermost OIDC (built-in)
Vikunja OIDC (built-in)
Plane OIDC (built-in)
GoToSocial OIDC (built-in)
Stirling-PDF OIDC (built-in)
Tandoor Recipes OIDC (built-in)
FreshRSS OIDC (built-in)
Any web service Forward-auth proxy (nginx auth_request)

Forward-Auth Proxy#

For apps without OIDC support, ATAuth provides nginx auth_request based SSO. Enable it in .env:

FORWARD_AUTH_ENABLED=true
FORWARD_AUTH_SESSION_SECRET=<generate-with-openssl-rand-hex-32>

Then configure nginx:

location / {
    auth_request /auth/verify;
    auth_request_set $auth_did $upstream_http_x_auth_did;
    auth_request_set $auth_handle $upstream_http_x_auth_handle;
    proxy_set_header X-Auth-DID $auth_did;
    proxy_set_header X-Auth-Handle $auth_handle;
    proxy_pass http://your-app;
}

location = /auth/verify {
    internal;
    proxy_pass http://atauth:3100;
    proxy_pass_request_body off;
    proxy_set_header Content-Length "";
    proxy_set_header X-Original-URL $scheme://$http_host$request_uri;
}

The admin dashboard generates these config snippets for you.

Self-Hosted PDS#

With a self-hosted PDS, ATAuth becomes a fully independent auth system:

  • Users get handles like @alice.your-domain.com
  • No dependency on Bluesky servers
  • Works on air-gapped networks
  • Same security model as enterprise OAuth

The gateway auto-discovers the user's PDS from their handle. No special configuration needed.

Architecture#

Component Description
Gateway Node.js/Express 5, TypeScript, SQLite
Identity AT Protocol OAuth (user's PDS)
OIDC Tokens ES256 signed JWTs
Proxy Cookies HMAC-SHA256 signed, typed
Access Control Deny-overrides, per-origin + global rules

Security#

  • No hardcoded secrets -- all sensitive config validated at startup
  • Client secrets stored as SHA-256 hashes
  • One-time flash tokens for secret display (never in URLs)
  • PKCE support (configurable per-client)
  • Constant-time comparison for all secret verification
  • HTML escaping on all server-rendered pages
  • HMAC-signed CSRF tokens on all dashboard forms
  • Rate limiting on auth endpoints
  • CSP with per-request nonces for inline scripts
  • WAF-compatible (Cloudflare Managed Ruleset + OWASP)

Documentation#

License#

MIT