Skip to content

CangioUni/traefik-passkey-plugin

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

3 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Traefik Passkey Authentication Plugin

⚠️ Important Notice: Due to Traefik plugin limitations that only allow standard library dependencies, this plugin implements a simplified WebAuthn verification. While it provides passkey authentication, it's recommended for internal/development use rather than production environments requiring full WebAuthn specification compliance.

For production deployments, consider using external authentication services or a full WebAuthn server with Traefik's ForwardAuth middleware.

A Traefik middleware plugin that provides WebAuthn/FIDO2 passkey authentication with user credentials specified in the plugin configuration.

Features

  • πŸ” Passkey Authentication: Modern passwordless authentication using WebAuthn
  • πŸ‘€ Configuration-Based Users: Define authorized users directly in Traefik config
  • πŸͺ Session Management: Cookie-based sessions with configurable timeout
  • 🎨 Built-in Login Page: Clean, responsive authentication UI
  • πŸ”’ Secure: HttpOnly, Secure cookies with SameSite protection
  • πŸ“¦ No External Dependencies: Uses only Go standard library

Limitations

  • Uses simplified ECDSA P-256 (ES256) signature verification
  • Public key extraction from COSE format is simplified
  • No support for RSA keys or other algorithms currently
  • Intended for internal/development use

Configuration

Plugin Configuration

Add the plugin to your Traefik static configuration:

# traefik.yml
experimental:
  plugins:
    passkey:
      moduleName: github.com/CangioUni/traefik-passkey-plugin
      version: v0.2.0

Middleware Configuration

Configure the middleware in your dynamic configuration:

# dynamic-config.yml
http:
  middlewares:
    passkey-auth:
      plugin:
        passkey:
          users:
            - id: "user-123"
              name: "john.doe"
              displayName: "John Doe"
              credentials:
                - id: "Y3JlZGVudGlhbC1pZA"  # Base64URL-encoded credential ID
                  publicKey: "pQECAyYgASFYIPr5..."  # Base64URL-encoded attestation object
                  signCount: 0
            - id: "user-456"
              name: "jane.smith"
              displayName: "Jane Smith"
              credentials:
                - id: "YW5vdGhlci1jcmVkZW50aWFs"
                  publicKey: "pQECAyYgASFYIC3m..."
                  signCount: 0
          rpDisplayName: "My Application"
          rpId: "example.com"
          rpOrigin: "https://example.com"
          cookieName: "traefik_passkey_session"
          cookieDomain: "example.com"
          sessionTimeout: 60  # minutes

  routers:
    my-router:
      rule: "Host(`example.com`)"
      service: my-service
      middlewares:
        - passkey-auth
      entryPoints:
        - websecure
      tls:
        certResolver: letsencrypt

  services:
    my-service:
      loadBalancer:
        servers:
          - url: "http://backend:8080"

Configuration Parameters

Parameter Type Required Default Description
users array βœ… - List of authorized users with their credentials
users[].id string βœ… - Unique user identifier
users[].name string βœ… - Username for login
users[].displayName string βœ… - User's display name
users[].credentials array βœ… - User's passkey credentials
users[].credentials[].id string βœ… - Base64URL credential ID
users[].credentials[].publicKey string βœ… - Base64URL attestation object
users[].credentials[].signCount int βœ… - Signature counter (start with 0)
rpDisplayName string ❌ "Traefik Passkey Auth" Relying party display name
rpId string βœ… - Relying party ID (domain)
rpOrigin string βœ… - Relying party origin (full URL)
cookieName string ❌ "traefik_passkey_session" Session cookie name
cookieDomain string ❌ "" Cookie domain
sessionTimeout int ❌ 60 Session timeout in minutes

Obtaining User Credentials

To add users to your configuration, you need to register their passkeys. Use the provided register.html file:

Registration Steps

  1. Serve the registration page:

    # For local testing
    python3 -m http.server 8080
    # Then open http://localhost:8080/register.html
    
    # For production, serve from your actual domain over HTTPS
  2. Register a passkey:

    • Open the registration page in your browser
    • Enter username, display name, and RP ID (must match your domain)
    • Click "Register Passkey"
    • Follow your device's authentication prompts
    • Copy the generated JSON configuration
  3. Add to Traefik configuration:

    • Paste the user object into your users array
    • Restart Traefik or reload the configuration

Example Output

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "name": "john.doe",
  "displayName": "John Doe",
  "credentials": [{
    "id": "dGVzdC1jcmVkZW50aWFsLWlk",
    "publicKey": "pQECAyYgASFYIFN...",
    "signCount": 0
  }]
}

Important Notes

  • HTTPS Required: Passkey registration requires HTTPS in production (localhost works for testing)
  • Domain Matching: The RP ID used during registration must match the domain where you'll use the passkey
  • Multiple Devices: Register each device separately and add all credentials to the same user

How It Works

  1. Unauthenticated Request: When a user accesses a protected route without a valid session, they're shown a login page
  2. Authentication Flow:
    • User enters their username
    • Plugin generates a WebAuthn challenge
    • User's authenticator (fingerprint, face recognition, security key) signs the challenge
    • Plugin verifies the signature against the configured public key
  3. Session Creation: On successful authentication, a secure session cookie is created
  4. Protected Access: Subsequent requests include the session cookie and are allowed through

Security Considerations

  1. HTTPS Required: Passkey authentication requires HTTPS in production
  2. Secure Cookies: Cookies are marked as HttpOnly, Secure, and use SameSite=Lax
  3. Challenge Expiry: Authentication challenges expire after 5 minutes
  4. Session Timeout: Sessions expire based on the configured timeout
  5. RP ID/Origin: Must match your domain exactly

Endpoints

The plugin creates special authentication endpoints:

  • /.auth/passkey/begin - Start authentication ceremony (POST)
  • /.auth/passkey/finish - Complete authentication (POST)
  • /.auth/passkey/logout - End session (GET/POST)

Docker Compose Example

version: '3.8'

services:
  traefik:
    image: traefik:v3.0
    command:
      - "--api.insecure=true"
      - "--providers.docker=true"
      - "--providers.file.directory=/config"
      - "--entrypoints.web.address=:80"
      - "--entrypoints.websecure.address=:443"
      - "--experimental.plugins.passkey.modulename=github.com/yourusername/traefik-passkey-plugin"
      - "--experimental.plugins.passkey.version=v1.0.0"
    ports:
      - "80:80"
      - "443:443"
      - "8080:8080"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - ./config:/config
      - ./certs:/certs

  app:
    image: nginx:alpine
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.app.rule=Host(`app.example.com`)"
      - "traefik.http.routers.app.entrypoints=websecure"
      - "traefik.http.routers.app.tls=true"
      - "traefik.http.routers.app.middlewares=passkey-auth"

Troubleshooting

"User not found" Error

  • Verify the username matches the name or id field in your configuration
  • Check for typos in the configuration

Authentication Fails

  • Ensure rpId matches your domain exactly (no protocol, no port)
  • Verify rpOrigin includes the full URL with protocol
  • Check that credentials were registered for the same domain
  • Confirm the public key is correctly base64-encoded

Session Not Persisting

  • Ensure cookies are enabled in the browser
  • Check cookieDomain matches your domain
  • Verify you're using HTTPS (required in production)

License

MIT License - See LICENSE file for details

Contributing

Contributions are welcome! Please open an issue or submit a pull request.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors