# Authentik Setup Guide

This guide walks you through configuring Authentik for OAuth 2.0 / OpenID Connect authentication with the Feuerwehr Dashboard.

## Table of Contents

- [Prerequisites](#prerequisites)
- [Authentik Installation](#authentik-installation)
- [Creating the Application](#creating-the-application)
- [Provider Configuration](#provider-configuration)
- [Redirect URIs Setup](#redirect-uris-setup)
- [Scopes Configuration](#scopes-configuration)
- [Getting Client Credentials](#getting-client-credentials)
- [Testing Authentication](#testing-authentication)
- [Common Issues](#common-issues)
- [Advanced Configuration](#advanced-configuration)

## Prerequisites

Before you begin, you need:

- An Authentik instance (self-hosted or cloud)
- Admin access to Authentik
- Your Feuerwehr Dashboard URL (e.g., `https://start.feuerwehr-rems.at`)
- Your backend API URL (e.g., `https://start.feuerwehr-rems.at`)

## Authentik Installation

If you don't have Authentik yet, here's a quick setup guide.

### Option 1: Docker Compose (Recommended)

Create `docker-compose.yml`:

```yaml
version: "3.8"

services:
  postgresql:
    image: postgres:16-alpine
    restart: unless-stopped
    volumes:
      - database:/var/lib/postgresql/data
    environment:
      POSTGRES_PASSWORD: ${PG_PASS:?database password required}
      POSTGRES_USER: ${PG_USER:-authentik}
      POSTGRES_DB: ${PG_DB:-authentik}
    env_file:
      - .env

  redis:
    image: redis:alpine
    restart: unless-stopped

  server:
    image: ghcr.io/goauthentik/server:2024.2
    restart: unless-stopped
    command: server
    environment:
      AUTHENTIK_SECRET_KEY: ${AUTHENTIK_SECRET_KEY}
      AUTHENTIK_POSTGRESQL__HOST: postgresql
      AUTHENTIK_POSTGRESQL__NAME: ${PG_DB:-authentik}
      AUTHENTIK_POSTGRESQL__USER: ${PG_USER:-authentik}
      AUTHENTIK_POSTGRESQL__PASSWORD: ${PG_PASS}
      AUTHENTIK_REDIS__HOST: redis
    ports:
      - "${AUTHENTIK_PORT_HTTP:-9000}:9000"
      - "${AUTHENTIK_PORT_HTTPS:-9443}:9443"
    depends_on:
      - postgresql
      - redis

  worker:
    image: ghcr.io/goauthentik/server:2024.2
    restart: unless-stopped
    command: worker
    environment:
      AUTHENTIK_SECRET_KEY: ${AUTHENTIK_SECRET_KEY}
      AUTHENTIK_POSTGRESQL__HOST: postgresql
      AUTHENTIK_POSTGRESQL__NAME: ${PG_DB:-authentik}
      AUTHENTIK_POSTGRESQL__USER: ${PG_USER:-authentik}
      AUTHENTIK_POSTGRESQL__PASSWORD: ${PG_PASS}
      AUTHENTIK_REDIS__HOST: redis
    depends_on:
      - postgresql
      - redis

volumes:
  database:
    driver: local
```

Create `.env`:

```bash
PG_PASS=<secure-database-password>
AUTHENTIK_SECRET_KEY=<generate-with-openssl-rand-base64-32>
AUTHENTIK_PORT_HTTP=9000
AUTHENTIK_PORT_HTTPS=9443
```

Start Authentik:

```bash
docker-compose up -d
```

Access Authentik at `http://localhost:9000` and complete the initial setup wizard.

### Option 2: Kubernetes

See [Authentik Kubernetes Documentation](https://goauthentik.io/docs/installation/kubernetes) for Helm charts.

## Creating the Application

### Step 1: Access Authentik Admin Interface

1. Log in to your Authentik instance
2. Navigate to **Admin Interface** (gear icon in top right)

### Step 2: Create Provider

1. In the admin panel, go to **Applications** → **Providers**
2. Click **Create** button
3. Select **OAuth2/OpenID Provider**

Configure the provider:

```
Name: Feuerwehr Dashboard Provider
Authorization Flow: default-provider-authorization-implicit-consent
Protocol Settings:
```

**Client Type**:
- Select: `Confidential`

**Client ID**:
- Auto-generated (you'll copy this later)
- Or set custom: `feuerwehr-dashboard`

**Client Secret**:
- Auto-generated (you'll copy this later)

**Redirect URIs**:
```
http://localhost:5173/auth/callback
http://localhost/auth/callback
https://start.feuerwehr-rems.at/auth/callback
```

Add one URI per line. Include all environments (development, staging, production).

**Signing Key**:
- Select: `authentik Self-signed Certificate` (default)

**Token Validity**:
```
Access token validity: 3600 (1 hour)
Refresh token validity: 86400 (24 hours)
```

Click **Create** to save the provider.

### Step 3: Create Application

1. Go to **Applications** → **Applications**
2. Click **Create** button

Configure the application:

```
Name: Feuerwehr Dashboard
Slug: feuerwehr-dashboard
Provider: Feuerwehr Dashboard Provider (select from dropdown)
Launch URL: https://start.feuerwehr-rems.at
```

**UI Settings** (optional):
```
Icon: (upload fire department logo)
Publisher: Your Fire Department Name
Description: Fire department operations dashboard
```

Click **Create** to save.

### Step 4: Configure Scopes

1. Go back to **Providers** → **Feuerwehr Dashboard Provider**
2. Scroll to **Advanced protocol settings**
3. Click **Edit** on **Scopes**

Ensure the following scopes are selected:

- [x] `openid` - Required for OpenID Connect
- [x] `profile` - User profile information
- [x] `email` - User email address

Optional scopes:
- [ ] `offline_access` - For refresh tokens (recommended)

Click **Update**.

## Provider Configuration

### Step 5: Configure Advanced Settings

Edit your provider and configure these advanced settings:

**Token Settings**:
```
Include claims in ID token: Yes
Access token validity: 3600 seconds (1 hour)
Refresh token validity: 86400 seconds (24 hours)
```

**Subject Mode**:
```
Based on the User's hashed ID
```

This ensures consistent user IDs.

**Signing Algorithm**:
```
RS256 (default)
```

### Step 6: Configure Claims

Ensure the following claims are mapped:

Standard claims (should be automatic):
- `sub` - Subject (user ID)
- `email` - User email
- `name` - Full name
- `preferred_username` - Username
- `given_name` - First name
- `family_name` - Last name

These are automatically included with the `profile` and `email` scopes.

## Redirect URIs Setup

Your redirect URIs must match exactly between Authentik and your application.

### Development Environment

```
http://localhost:5173/auth/callback
```

This is the Vite dev server URL.

### Production Environment

```
https://start.feuerwehr-rems.at/auth/callback
```

Replace `feuerwehr-rems.at` with your actual domain.

### Docker Local Testing

```
http://localhost/auth/callback
http://localhost:80/auth/callback
```

For testing the production Docker build locally.

### Important Notes

- URLs are **case-sensitive**
- Must include protocol (`http://` or `https://`)
- No trailing slashes
- Port numbers must match if specified

## Scopes Configuration

### Required Scopes

Your application requires these scopes:

1. **openid** - Identifies this as an OpenID Connect request
2. **profile** - Provides basic profile information
3. **email** - Provides user email address

### Requesting Scopes

The dashboard automatically requests these scopes in the OAuth flow.

Backend configuration (`backend/src/config/oauth.ts`):
```typescript
scopes: ['openid', 'profile', 'email']
```

Frontend login flow (`frontend/src/services/authService.ts`):
```typescript
const scopes = 'openid profile email';
```

## Getting Client Credentials

### Step 7: Copy Client Credentials

1. Go to **Applications** → **Providers**
2. Click on **Feuerwehr Dashboard Provider**
3. Find the **Client ID** and **Client Secret**

**Client ID**: Will look like `abc123def456...` or custom `feuerwehr-dashboard`

**Client Secret**: Click the **eye icon** to reveal, then **copy button**

### Step 8: Get Provider URLs

1. In the provider details, find **OpenID Configuration URL**:
   ```
   https://auth.firesuite.feuerwehr-rems.at/application/o/feuerwehr-dashboard/.well-known/openid-configuration
   ```

2. Important URLs from this configuration:
   - **Issuer**: `https://auth.firesuite.feuerwehr-rems.at/application/o/feuerwehr-dashboard/`
   - **Authorization Endpoint**: Auto-discovered
   - **Token Endpoint**: Auto-discovered
   - **Userinfo Endpoint**: Auto-discovered

### Step 9: Configure Dashboard

Update your Feuerwehr Dashboard `.env` file:

```bash
# Authentik OAuth Configuration
AUTHENTIK_CLIENT_ID=<your-client-id>
AUTHENTIK_CLIENT_SECRET=<your-client-secret>
AUTHENTIK_ISSUER=https://auth.firesuite.feuerwehr-rems.at/application/o/feuerwehr-dashboard/
AUTHENTIK_REDIRECT_URI=https://start.feuerwehr-rems.at/auth/callback

# For development, use:
# AUTHENTIK_ISSUER=http://localhost:9000/application/o/feuerwehr-dashboard/
# AUTHENTIK_REDIRECT_URI=http://localhost:5173/auth/callback
```

**Important**: The `AUTHENTIK_ISSUER` must end with a trailing slash `/`.

## Testing Authentication

### Step 10: Test the Flow

1. **Start your application**:
   ```bash
   # Development
   cd backend && npm run dev
   cd frontend && npm run dev

   # Or production
   make prod
   ```

2. **Open the dashboard** in your browser:
   ```
   Development: http://localhost:5173
   Production: https://start.feuerwehr-rems.at
   ```

3. **Click "Login" button**

4. **You should be redirected to Authentik** login page

5. **Enter your Authentik credentials**

6. **Consent screen** (if enabled):
   - Review permissions
   - Click "Authorize"

7. **Redirect back to dashboard**:
   - Should show your dashboard
   - User profile should be loaded
   - Check browser console for any errors

### Step 11: Verify Token Exchange

Check backend logs:

```bash
make logs-prod
# or
cd backend && npm run dev
```

Look for:
```
[INFO] OAuth callback received
[INFO] Token exchange successful
[INFO] User authenticated: <username>
```

### Step 12: Test User Profile

In the dashboard:
1. Navigate to Profile page
2. Verify your information is displayed:
   - Username
   - Email
   - Name

### Step 13: Test Logout

1. Click "Logout" button
2. Should redirect to login page
3. Verify session is cleared
4. Attempting to access dashboard should redirect to login

## Common Issues

### Issue 1: Redirect URI Mismatch

**Error**: `redirect_uri_mismatch` or `invalid_redirect_uri`

**Solution**:
1. Check the redirect URI in Authentik **exactly** matches your app
2. Include protocol (`http://` or `https://`)
3. Check for trailing slashes
4. Verify port numbers match

### Issue 2: Invalid Client Credentials

**Error**: `invalid_client`

**Solution**:
1. Verify `AUTHENTIK_CLIENT_ID` is correct
2. Verify `AUTHENTIK_CLIENT_SECRET` is correct (no extra spaces)
3. Check if client secret was regenerated in Authentik
4. Ensure client type is "Confidential"

### Issue 3: CORS Errors

**Error**: CORS policy blocked request

**Solution**:
1. Ensure `CORS_ORIGIN` in backend `.env` matches frontend URL
2. For development: `CORS_ORIGIN=http://localhost:5173`
3. For production: `CORS_ORIGIN=https://start.feuerwehr-rems.at`
4. Restart backend after changing CORS settings

### Issue 4: Token Validation Failed

**Error**: `Invalid token` or `Token signature verification failed`

**Solution**:
1. Verify `AUTHENTIK_ISSUER` URL is correct
2. Ensure issuer URL ends with `/`
3. Check Authentik is accessible from backend server
4. Verify JWT signing key hasn't changed

### Issue 5: Scope Errors

**Error**: `invalid_scope` or missing user data

**Solution**:
1. Ensure `openid`, `profile`, `email` scopes are configured in Authentik
2. Check scopes are requested in login flow
3. Verify user has consented to scopes

### Issue 6: User Not Created in Database

**Error**: Authentication works but user not found

**Solution**:
1. Check backend logs for database errors
2. Verify database migrations ran
3. Check `users` table exists:
   ```bash
   docker exec -it feuerwehr_db_prod psql -U prod_user -d feuerwehr_prod -c "\dt"
   ```
4. Manually run migrations if needed

### Issue 7: Token Refresh Fails

**Error**: Refresh token invalid or expired

**Solution**:
1. Check token validity settings in Authentik
2. Increase refresh token validity (e.g., 86400 seconds)
3. Verify `offline_access` scope is included
4. Clear browser cookies and re-authenticate

## Advanced Configuration

### Customizing Login Flow

Create custom authentication flow in Authentik:

1. Go to **Flows & Stages** → **Flows**
2. Duplicate `default-provider-authorization-implicit-consent`
3. Add custom stages (MFA, email verification, etc.)
4. Update provider to use custom flow

### Adding Multi-Factor Authentication

1. Go to **Flows & Stages** → **Stages**
2. Create authenticator validation stage
3. Add to your authorization flow
4. Users will be prompted for MFA on login

### Branding

Customize Authentik appearance:

1. Go to **System** → **Branding**
2. Upload logo
3. Set primary color to match fire department branding
4. Configure footer links

### User Management

Add users to Authentik:

1. Go to **Directory** → **Users**
2. Click **Create**
3. Fill in user details
4. Set password
5. Assign to groups (if using RBAC)

### Group-Based Access Control

Implement role-based access:

1. Create groups in **Directory** → **Groups**
2. Assign users to groups
3. In your app, read `groups` claim from token
4. Implement authorization based on groups

Example groups:
- `feuerwehr-admin` - Full access
- `feuerwehr-operator` - Standard access
- `feuerwehr-viewer` - Read-only access

## Testing Checklist

After configuration, verify:

- [ ] Login redirects to Authentik
- [ ] Successful authentication redirects back
- [ ] User profile loads correctly
- [ ] Tokens are stored securely
- [ ] Logout clears session
- [ ] Token refresh works
- [ ] Protected routes require authentication
- [ ] Invalid tokens are rejected
- [ ] CORS is properly configured
- [ ] Works on all browsers (Chrome, Firefox, Safari)

## Configuration Reference

### Minimum Required Settings

**Authentik Provider**:
```
Client Type: Confidential
Client ID: <auto-generated>
Client Secret: <auto-generated>
Redirect URIs: https://start.feuerwehr-rems.at/auth/callback
Scopes: openid, profile, email
Access Token Validity: 3600
Refresh Token Validity: 86400
```

**Dashboard .env**:
```bash
AUTHENTIK_CLIENT_ID=<from-authentik>
AUTHENTIK_CLIENT_SECRET=<from-authentik>
AUTHENTIK_ISSUER=https://auth.firesuite.feuerwehr-rems.at/application/o/feuerwehr-dashboard/
AUTHENTIK_REDIRECT_URI=https://start.feuerwehr-rems.at/auth/callback
```

## Security Best Practices

1. **Use HTTPS in production** - Never use HTTP for OAuth flows
2. **Keep secrets secret** - Never commit credentials to Git
3. **Rotate secrets regularly** - Change client secrets periodically
4. **Use strong passwords** - For Authentik admin and users
5. **Enable MFA** - Require multi-factor authentication for admin users
6. **Monitor logs** - Watch for failed login attempts
7. **Limit token validity** - Use short-lived access tokens
8. **Validate redirect URIs** - Only allow known URLs

## Additional Resources

- [Authentik Documentation](https://goauthentik.io/docs/)
- [OAuth 2.0 Specification](https://oauth.net/2/)
- [OpenID Connect](https://openid.net/connect/)
- [Authentik Community Forum](https://github.com/goauthentik/authentik/discussions)

## Support

If you encounter issues:

1. Check Authentik logs: `docker-compose logs -f server`
2. Check dashboard backend logs: `make logs-prod`
3. Review browser console for errors
4. Consult [Common Issues](#common-issues) section
5. Search Authentik GitHub issues
6. Create detailed issue report

---

**Next Steps**: After completing Authentik setup, proceed to [DEPLOYMENT.md](DEPLOYMENT.md) for production deployment.
