# Proxy Authentication

Pulse supports proxy-based authentication for integration with SSO providers like Authentik, Authelia, Caddy, and others. This allows you to authenticate users via your existing reverse proxy authentication system while maintaining security.

> **When to use this**: If you already have an authentication proxy (Authentik, Authelia, etc.) protecting your services and want Pulse to trust that authentication instead of requiring its own login.

## Quick Start

1. Set `PROXY_AUTH_SECRET` to a random secret string
2. Configure your proxy to send this secret in the `X-Proxy-Secret` header
3. Set `PROXY_AUTH_USER_HEADER` to match your proxy's username header
4. (Optional) Configure role-based access control with `PROXY_AUTH_ROLE_HEADER`

## Configuration

Set the following environment variables to enable proxy authentication:

### Required Settings

```bash
# Shared secret between proxy and Pulse (required)
PROXY_AUTH_SECRET=your-secure-secret-here

# Header containing the authenticated username (optional but recommended)
PROXY_AUTH_USER_HEADER=X-Authentik-Username
```

### Optional Settings

```bash
# Header containing user roles/groups
PROXY_AUTH_ROLE_HEADER=X-Authentik-Groups

# Separator for multiple roles (default: |)
PROXY_AUTH_ROLE_SEPARATOR=|

# Role name that grants admin access (default: admin)
PROXY_AUTH_ADMIN_ROLE=admin

# URL to redirect users to for logout
PROXY_AUTH_LOGOUT_URL=/outpost.goauthentik.io/sign_out
```

## How It Works

1. **User visits Pulse** → Your proxy intercepts the request
2. **Proxy authenticates user** → Via its own login page/SSO
3. **Proxy adds headers** to the request:
   - `X-Proxy-Secret`: Shared secret (prevents spoofing)
   - Username header (e.g., `X-Authentik-Username`)
   - Roles header (e.g., `X-Authentik-Groups`)
4. **Pulse validates** the secret and trusts the user identity
5. **No Pulse login required** → User sees the dashboard immediately

## Example Configurations

### Authentik with Traefik

```yaml
# docker-compose.yml environment variables
environment:
  - PROXY_AUTH_SECRET=your-secure-secret-here
  - PROXY_AUTH_USER_HEADER=X-Authentik-Username
  - PROXY_AUTH_ROLE_HEADER=X-Authentik-Groups
  - PROXY_AUTH_ROLE_SEPARATOR=|
  - PROXY_AUTH_ADMIN_ROLE=admin
  - PROXY_AUTH_LOGOUT_URL=/outpost.goauthentik.io/sign_out
```

Traefik middleware configuration:

```yaml
http:
  middlewares:
    proxy-header-secret:
      headers:
        customRequestHeaders:
          X-Proxy-Secret: "your-secure-secret-here"
    
    authentik-auth:
      forwardAuth:
        address: http://authentik:9000/outpost.goauthentik.io/auth/traefik
        trustForwardHeader: true
        authResponseHeaders:
          - X-Authentik-Username
          - X-Authentik-Groups
          - X-Authentik-Email

  routers:
    pulse:
      rule: Host(`pulse.example.com`)
      entryPoints:
        - websecure
      middlewares:
        - authentik-auth
        - proxy-header-secret
      service: pulse-service
    
    pulse-auth:
      rule: Host(`pulse.example.com`) && PathPrefix(`/outpost.goauthentik.io/`)
      entryPoints:
        - websecure
      service: authentik-outpost
```

### Authelia Example

```yaml
# docker-compose.yml environment variables
environment:
  - PROXY_AUTH_SECRET=your-secure-secret-here
  - PROXY_AUTH_USER_HEADER=Remote-User
  - PROXY_AUTH_ROLE_HEADER=Remote-Groups
  - PROXY_AUTH_ROLE_SEPARATOR=,
  - PROXY_AUTH_ADMIN_ROLE=admins
  - PROXY_AUTH_LOGOUT_URL=/logout
```

Nginx configuration:
```nginx
location / {
    # Authelia authorization
    auth_request /authelia;
    auth_request_set $user $upstream_http_remote_user;
    auth_request_set $groups $upstream_http_remote_groups;
    
    # Pass headers to Pulse
    proxy_set_header X-Proxy-Secret "your-secure-secret-here";
    proxy_set_header Remote-User $user;
    proxy_set_header Remote-Groups $groups;
    
    proxy_pass http://pulse:7655;
}
```

### Caddy with Forward Auth

```caddyfile
pulse.example.com {
    forward_auth authelia:9091 {
        uri /api/verify?rd=https://auth.example.com
        copy_headers Remote-User Remote-Groups
    }
    
    header_downstream X-Proxy-Secret "your-secure-secret-here"
    
    reverse_proxy pulse:7655
}
```

### Nginx Proxy Manager

In NPM's Advanced tab for your Pulse proxy host:

```nginx
# Custom Nginx Configuration
proxy_set_header X-Proxy-Secret "your-secure-secret-here";
proxy_set_header X-Authentik-Username $http_x_authentik_username;
proxy_set_header X-Authentik-Groups $http_x_authentik_groups;
```

## Security Considerations

1. **Use a strong secret**: Generate a secure random string for `PROXY_AUTH_SECRET`
2. **HTTPS only**: Always use HTTPS between the proxy and Pulse in production
3. **Network isolation**: Ensure Pulse is not directly accessible, only through the proxy
4. **Header validation**: Pulse validates all headers and the proxy secret on every request

## Combining with Other Auth Methods

Proxy authentication can work alongside other authentication methods:

- If `PROXY_AUTH_SECRET` is set, proxy auth takes precedence
- API tokens (`API_TOKEN`) still work for programmatic access
- Basic auth (`PULSE_AUTH_USER`/`PULSE_AUTH_PASS`) can be used as fallback

## Troubleshooting

### Users can't access Pulse (401 Unauthorized)

1. **Check the secret header**:
   ```bash
   # Test with curl
   curl -H "X-Proxy-Secret: your-secret" \
        -H "X-Authentik-Username: testuser" \
        http://pulse:7655/api/state
   ```

2. **Verify headers are being sent**:
   - Enable debug logging: `LOG_LEVEL=debug`
   - Check Pulse logs: `docker logs pulse` or `journalctl -u pulse`
   - Look for "Invalid proxy secret" or "Proxy auth user header not found"

3. **Common issues**:
   - Typo in `PROXY_AUTH_SECRET` 
   - Header names are case-sensitive in configuration
   - Proxy not forwarding headers correctly

### Admin features not available

Check if user is recognized as admin:
```bash
curl -H "X-Proxy-Secret: your-secret" \
     -H "X-Authentik-Username: admin" \
     -H "X-Authentik-Groups: users|admin" \
     http://pulse:7655/api/security/status | jq '.proxyAuthIsAdmin'
```

- Ensure the roles header contains the admin role
- Verify `PROXY_AUTH_ADMIN_ROLE` matches your configuration  
- Check the role separator matches your proxy's format (default: `|`)

### Logout doesn't work

- Verify `PROXY_AUTH_LOGOUT_URL` points to your proxy's logout endpoint
- Ensure the logout URL is accessible from the user's browser
- For Authentik: `/outpost.goauthentik.io/sign_out`
- For Authelia: `/logout` or custom path

### Testing your configuration

Test proxy auth without a reverse proxy:
```bash
# Should return 401
curl http://localhost:7655/api/state

# Should return 200 with state data
curl -H "X-Proxy-Secret: your-secret-here" \
     -H "X-Your-User-Header: testuser" \
     http://localhost:7655/api/state
```

## FAQ

**Q: Do I still need to set up Pulse authentication?**  
A: No, when proxy auth is configured, Pulse trusts your proxy's authentication. Users won't see Pulse's login page.

**Q: Can I use this with Cloudflare Access or Tailscale?**  
A: Yes, any service that can add custom headers after authentication will work.

**Q: What happens if someone bypasses my proxy?**  
A: They can't authenticate. Without the correct `X-Proxy-Secret` header, all requests are rejected with 401.

**Q: Can I have some users with read-only access?**  
A: Currently, Pulse has admin and non-admin roles. Non-admin users have read-only access to monitoring data.

**Q: Is the username displayed in Pulse?**  
A: Yes, the authenticated username appears in the top-right corner of the UI.

**Q: Can I use both proxy auth and API tokens?**  
A: Yes! API tokens still work for automation/scripts. Proxy auth is for human users via the web UI.