![]()
RAuth is a lightweight, high-performance authentication proxy and user management system written in Go. It is specifically architected to provide a centralized, secure access control layer for self-hosted infrastructure via the Nginx auth_request module.
RAuth eliminates the complexity of full-scale identity providers while maintaining enterprise-grade security standards like Passkey (WebAuthn) support, AES-256-GCM session encryption, and real-time Prometheus observability.
🔐 Multi-Factor Authentication
|
🌐 Smart Session Management
|
🛠️ Administrative Control
|
🎨 Glassmorphism "Matrix" UI
|
[!NOTE] Browser & Device Support: Passkeys are supported on Chrome 67+, Edge 79+, Firefox 60+, and Safari 13+. Hardware keys (YubiKey) work across all platforms, while platform authenticators (TouchID, Windows Hello) require OS-level support.
RAuth integrates seamlessly into your existing Nginx proxy stack using the auth_request module.
%%{init: {'theme': 'dark', 'themeVariables': { 'primaryColor': '#dc3545', 'primaryTextColor': '#fff', 'lineColor': '#ef4444', 'nodeBorder': '#dc3545', 'mainBkg': '#1f1f1f', 'actorBkg': '#1f1f1f' }}}%%
graph TD
User((User)) -->|HTTPS Request| Nginx[Nginx Reverse Proxy]
Nginx -->|1. auth_request| RAuth[RAuth Auth Service]
RAuth <-->|2. Session Check| Redis[(Redis Store)]
RAuth -->|3. Return 200/401| Nginx
Nginx -->|4. If 200: Forward| Backend[Your App Backend]
Nginx -->|5. If 401: Redirect| Login[RAuth Login UI]
RAuth is built with a "Security-First" mindset, implementing advanced system-wide hardening:
SERVER_SECRET before being stored in Redis, protecting against database exposure.RAuth acts as an "Authorizer" for Nginx. When a request hits your proxy, Nginx performs a lightweight subrequest to RAuth to verify the user's session.
# 1. Define the RAuth validation endpoint
location = /rauth-verify {
internal;
proxy_pass http://rauth-auth-service/rauthvalidate;
proxy_pass_request_body off;
proxy_set_header Content-Length "";
proxy_set_header X-Original-URI $request_uri;
# Forward the real client IP on the subrequest so rauth logs/acts on it
# instead of nginx's own address. Pair with TRUST_X_REAL_IP=true (or
# TRUST_X_FORWARDED_FOR=true) on the rauth container.
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
# 2. Protect your application
location / {
auth_request /rauth-verify;
# Propagate user identity to your backend
auth_request_set $user $upstream_http_x_rauth_user;
proxy_set_header X-User $user;
# REQUIRED for Automatic Token Rotation:
# Propagate Set-Cookie from RAuth back to the client
auth_request_set $new_cookie $upstream_http_set_cookie;
add_header Set-Cookie $new_cookie;
# Handle unauthorized users
error_page 401 = @error401;
proxy_pass http://your-app-backend;
}
location @error401 {
return 302 https://auth.yourdomain.com/rauthlogin?rd=$scheme://$http_host$request_uri;
}
[!IMPORTANT] The RAuth host must NOT be behind
auth_request. Serveauth.yourdomain.com(its/rauthlogin,/rauthmgmt, and static asset routes) as a plainproxy_passto RAuth. If the login page itself requires authentication, every unauthenticated visit returns 401 and redirects back to the login page — an infinite loop the user can never escape. Only protect your other applications with theauth_requestsubrequest.
RAuth's only peer is your proxy (e.g. the Docker bridge 172.x.x.x), so the real client IP must arrive in a header nginx sets. With no TRUST_* flag, RAuth uses smart mode, which rejects private forwarded IPs — so a direct LAN client (192.168.x/10.x) is dropped and you "only see the Docker IP".
If your service is reachable both through Cloudflare and directly (LAN/Tailscale bypassing Cloudflare), do not set TRUST_CLOUDFLARE_IP — RAuth can't distinguish the two paths (its peer is always nginx), so a direct client could spoof CF-Connecting-IP. Instead, let nginx resolve the visitor and forward a single authoritative X-Real-IP:
# Scope realip to Cloudflare's ranges ONLY (https://www.cloudflare.com/ips/),
# so direct LAN/Tailscale connections keep their real $remote_addr while
# Cloudflare traffic is rewritten to the true visitor IP.
set_real_ip_from 173.245.48.0/20;
set_real_ip_from 103.21.244.0/22;
# ... (full IPv4 + IPv6 list from cloudflare.com/ips) ...
set_real_ip_from 2c0f:f248::/32;
real_ip_header CF-Connecting-IP;
real_ip_recursive on;
# Forward the resolved client IP to RAuth on the auth subrequest:
# proxy_set_header X-Real-IP $remote_addr;
Then set TRUST_X_REAL_IP=true on the RAuth container. This is safe because nginx overwrites X-Real-IP with $remote_addr, which a client cannot spoof through the proxy. The full annotated config is in nginx-proxy-example.conf.
Caddy features a built-in forward_auth directive that makes integrating RAuth incredibly straightforward.
# Protect app.example.com using RAuth
app.example.com {
# 1. Forward validation request to RAuth's endpoint
forward_auth http://rauth-auth-service:5980 {
uri /rauthvalidate
copy_headers X-RAuth-User
}
# 2. Reverse proxy to your backend service if authorized
reverse_proxy http://your-app-backend:8080
}
Traefik uses a ForwardAuth middleware layer. You define the middleware on the RAuth service and reference it on the router of the application you want to protect.
```yaml services: # 1. Define the RAuth service and middleware labels rauth: image: ghcr.io/arumes31/rauth-auth:latest container_name: rauth-auth-service labels: - "traefik.http.middlewares.rauth-auth.forwardauth.address=http://rauth-auth-service:5980/rauthvalidate" - "traefik.http.middlewares.rauth-auth.forwardauth.trustForwardHeader=true" - "traefik.http.middlewares.rauth-auth.forwardauth.authResponseHeaders=X-RAuth-User"
# 2. Reference the middleware to protect your application your-app: image: your-app-image:latest lab
—
$ claude mcp add rauth \
-- python -m otcore.mcp_server <graph>