Skip to main content

User Authentication

User authentication in Frontier is designed for human users accessing your application through a web browser or mobile app. Frontier provides multiple authentication strategies that you can enable and configure based on your application’s needs.

Supported Authentication Strategies

Frontier supports the following user authentication strategies:
  1. Social Login (OIDC) - Google, GitHub, Facebook, and other OIDC providers
  2. Email OTP - One-time password sent via email
  3. Magic Links - Passwordless login via email link
  4. Passkeys - WebAuthn-based biometric and hardware key authentication

Listing Available Strategies

Before presenting login options to users, query Frontier to get the list of enabled authentication strategies:
curl --location 'http://localhost:7400/v1beta1/auth' \
  --header 'Accept: application/json'
Response:
{
  "methods": [
    "google",
    "github",
    "mailotp",
    "maillink",
    "passkey"
  ]
}

Social Login (OIDC)

Social login allows users to authenticate using their existing accounts from providers like Google, GitHub, or Facebook.

Configuration

Configure OIDC providers in your config.yaml:
app:
  authentication:
    callback_urls:
      - "https://frontier.example.com/v1beta1/auth/callback"
    oidc_config:
      google:
        client_id: "xxxxx.apps.googleusercontent.com"
        client_secret: "xxxxx"
        issuer_url: "https://accounts.google.com"
        validity: "10m"
      github:
        client_id: "xxxxx"
        client_secret: "xxxxx"
        issuer_url: "https://github.com"
        validity: "10m"

Setting Up Google OIDC

1
Create a Google Cloud Project
2
Visit the Google Cloud Console and create a new project.
3
Create OAuth 2.0 Credentials
4
  • Navigate to Credentials in the sidebar
  • Click Create credentials → OAuth client ID
  • Select Web application as the application type
  • Add your callback URL to Authorized redirect URIs:
    https://frontier.example.com/v1beta1/auth/callback
    
  • 5
    Copy Credentials
    6
    Copy the Client ID and Client Secret to your Frontier configuration.
    7
    Update Configuration
    8
    Add the Google OIDC configuration to your config.yaml as shown above.

    Authentication Flow

    1
    Start Authentication
    2
    Request the authentication URL from Frontier:
    3
    curl --location 'http://localhost:7400/v1beta1/auth/register/google?callback_url=https://frontier.example.com/v1beta1/auth/callback&return_to=https://app.example.com/dashboard' \
      --header 'Accept: application/json'
    
    4
    Response:
    5
    {
      "endpoint": "https://accounts.google.com/o/oauth2/v2/auth?client_id=...&redirect_uri=...",
      "state": "flow-uuid-here"
    }
    
    6
    Redirect User
    7
    Redirect the user to the endpoint URL. This takes them to Google’s login page.
    8
    User Authenticates
    9
    User enters their Google credentials and approves access.
    10
    Handle Callback
    11
    Google redirects back to your callback URL with a code and state:
    12
    https://frontier.example.com/v1beta1/auth/callback?code=AUTH_CODE&state=FLOW_STATE
    
    13
    Frontier automatically processes this callback, verifies the code, and creates/retrieves the user.
    14
    Session Created
    15
    Frontier creates an encrypted session cookie and redirects to your return_to URL:
    16
    Set-Cookie: frontier-session=encrypted-session-data; HttpOnly; Secure; SameSite=Lax
    Location: https://app.example.com/dashboard
    
    17
    Access Granted
    18
    User is now authenticated! All subsequent requests include the session cookie.

    Complete Example

    import { useState, useEffect } from 'react';
    
    function LoginPage() {
      const [strategies, setStrategies] = useState([]);
    
      useEffect(() => {
        // Fetch available strategies
        fetch('http://localhost:7400/v1beta1/auth')
          .then(res => res.json())
          .then(data => setStrategies(data.methods));
      }, []);
    
      const handleGoogleLogin = async () => {
        const callbackUrl = 'https://frontier.example.com/v1beta1/auth/callback';
        const returnTo = 'https://app.example.com/dashboard';
        
        const response = await fetch(
          `http://localhost:7400/v1beta1/auth/register/google?callback_url=${callbackUrl}&return_to=${returnTo}`
        );
        
        const data = await response.json();
        
        // Redirect to Google login
        window.location.href = data.endpoint;
      };
    
      return (
        <div>
          <h1>Sign In</h1>
          {strategies.includes('google') && (
            <button onClick={handleGoogleLogin}>
              Sign in with Google
            </button>
          )}
        </div>
      );
    }
    

    Email One-Time Password (OTP)

    Email OTP provides passwordless authentication by sending a one-time code to the user’s email.

    Configuration

    app:
      authentication:
        mail_otp:
          subject: "Your Login Code"
          body: "Your one-time password is: <h2>{{.Otp}}</h2><br>This code expires in 10 minutes."
          validity: "10m"
          
      mailer:
        smtp_host: "smtp.gmail.com"
        smtp_port: 587
        smtp_username: "[email protected]"
        smtp_password: "xxxxx"
        headers:
          from: "[email protected]"
    

    Authentication Flow

    1
    Request OTP
    2
    Send a request with the user’s email:
    3
    curl --location 'http://localhost:7400/v1beta1/auth/register/[email protected]' \
      --header 'Accept: application/json'
    
    4
    Response:
    5
    {
      "state": "flow-uuid-here"
    }
    
    6
    User Receives Email
    7
    Frontier sends an email with the OTP code to the user.
    8
    Submit OTP
    9
    User enters the OTP code in your application, which submits it to Frontier:
    10
    curl --location 'http://localhost:7400/v1beta1/auth/callback?code=123456&state=flow-uuid-here' \
      --header 'Accept: application/json'
    
    11
    Verification
    12
    Frontier verifies the OTP code. If valid, creates/retrieves the user and establishes a session.
    13
    Response:
    14
    Set-Cookie: frontier-session=encrypted-session-data; HttpOnly; Secure
    

    Security Features

    • Rate Limiting - Maximum 3 OTP verification attempts per flow
    • Time Expiration - OTP expires after 10 minutes (configurable)
    • Constant-Time Comparison - Prevents timing attacks
    • Flow Consumption - OTP can only be used once

    Example Implementation

    function EmailOTPLogin() {
      const [email, setEmail] = useState('');
      const [otp, setOtp] = useState('');
      const [state, setState] = useState(null);
      const [step, setStep] = useState('email');
    
      const handleSendOTP = async () => {
        const response = await fetch(
          `http://localhost:7400/v1beta1/auth/register/mailotp?email=${email}`
        );
        const data = await response.json();
        setState(data.state);
        setStep('otp');
      };
    
      const handleVerifyOTP = async () => {
        const response = await fetch(
          `http://localhost:7400/v1beta1/auth/callback?code=${otp}&state=${state}`
        );
        
        if (response.ok) {
          // Session cookie set automatically
          window.location.href = '/dashboard';
        }
      };
    
      return (
        <div>
          {step === 'email' && (
            <div>
              <input
                type="email"
                value={email}
                onChange={(e) => setEmail(e.target.value)}
                placeholder="Enter your email"
              />
              <button onClick={handleSendOTP}>Send Code</button>
            </div>
          )}
          
          {step === 'otp' && (
            <div>
              <input
                type="text"
                value={otp}
                onChange={(e) => setOtp(e.target.value)}
                placeholder="Enter 6-digit code"
              />
              <button onClick={handleVerifyOTP}>Verify</button>
            </div>
          )}
        </div>
      );
    }
    
    Magic links provide one-click authentication via email.

    Configuration

    app:
      authentication:
        mail_link:
          subject: "Sign in to Your Account"
          body: "Click the link below to sign in:<br><a href='{{.Link}}'>Sign In</a><br>This link expires in 10 minutes."
          validity: "10m"
    

    Authentication Flow

    curl --location 'http://localhost:7400/v1beta1/auth/register/[email protected]&callback_url=https://frontier.example.com/v1beta1/auth/callback' \
      --header 'Accept: application/json'
    
    Frontier sends an email with a unique link. When clicked, the user is automatically authenticated.

    Passkey Authentication

    Passkeys provide modern, phishing-resistant authentication using WebAuthn.

    Features

    • Biometric authentication (fingerprint, face recognition)
    • Hardware security keys (YubiKey, etc.)
    • Platform authenticators (Touch ID, Windows Hello)
    • No passwords to remember

    Flow

    1
    Start Registration
    2
    curl --location 'http://localhost:7400/v1beta1/auth/register/[email protected]' \
      --header 'Accept: application/json'
    
    3
    Create Credential
    4
    Browser prompts user to create a passkey using their biometric or security key.
    5
    Complete Registration
    6
    Submit the credential data back to Frontier to complete registration.
    7
    Future Logins
    8
    User can authenticate with just their biometric/security key.

    Request Verification

    After successful authentication, you can verify requests in two ways: The session cookie is automatically included in requests:
    curl --location 'http://localhost:7400/v1beta1/users/self' \
      --header 'Cookie: frontier-session=encrypted-data'
    

    2. Access Token

    Request an access token after authentication:
    curl --location --request POST 'http://localhost:7400/v1beta1/auth/token' \
      --header 'Cookie: frontier-session=encrypted-data'
    
    Response:
    {
      "access_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6IjE2ODAyMzgyNDQyOTQiLCJ0eXAiOiJKV1QifQ...",
      "token_type": "Bearer"
    }
    
    Use the access token in subsequent requests:
    curl --location 'http://localhost:7400/v1beta1/users/self' \
      --header 'Authorization: Bearer eyJhbGci...'
    

    Logout

    To end a user’s session:
    curl --location --request POST 'http://localhost:7400/v1beta1/auth/logout' \
      --header 'Cookie: frontier-session=encrypted-data'
    

    Multi-Organization Support

    Frontier is multi-tenant aware. Each organization can have different authentication requirements:
    # Organization-level settings (via API)
    {
      "org_id": "org-123",
      "allowed_strategies": ["google", "mailotp"],
      "require_2fa": true
    }
    

    Best Practices

    Always use HTTPS in production to protect session cookies and tokens.
    app:
      authentication:
        session:
          secure: true
          same_site: "strict"
    
    Frontier includes CSRF protection. Ensure your frontend handles CSRF tokens properly.
    Only allow trusted callback URLs to prevent open redirect vulnerabilities.
    authentication:
      callback_urls:
        - "https://app.example.com/auth/callback"
    
    Use short-lived access tokens and longer-lived refresh tokens.
    authentication:
      token:
        validity: "1h"  # Short-lived access tokens
      session:
        validity: "168h"  # 7-day sessions
    

    Sessions

    Learn about session management and lifecycle

    Service Users

    Authenticate machine users and services

    Build docs developers (and LLMs) love