Home Realm Discovery

Email-based SSO routing for automatic identity provider detection

Updated Dec 29, 2025 Edit this page

Home Realm Discovery (HRD)

Home Realm Discovery enables automatic routing of users to their organization’s identity provider based on their email domain.

Overview

When a user enters their email address, HRD checks if the email domain is associated with a configured upstream identity provider. If a match is found, the user is redirected to their organization’s SSO provider instead of seeing the password login form.

sequenceDiagram
    participant User
    participant Client
    participant AuthOS
    participant IdP

    User->>Client: Enter email
    Client->>AuthOS: POST /api/auth/lookup-email
    AuthOS-->>Client: {redirect_to: "github", org: "acme"}
    Client->>AuthOS: GET /auth/github?org=acme&service=app
    AuthOS-->>IdP: Redirect to IdP
    IdP-->>AuthOS: OAuth callback
    AuthOS-->>Client: Tokens

Endpoints

POST /api/auth/lookup-email

Look up email domain to determine authentication method.

Synopsis

Property Value
Authentication Public
Rate Limit 10 requests/minute per IP
Idempotent Yes

Request Body

Field Type Required Description
email string Yes User’s email address
org_slug string Yes Organization slug
service_slug string Yes Service slug

Example Request

curl -X POST https://sso.example.com/api/auth/lookup-email \
  -H "Content-Type: application/json" \
  -d '{
    "email": "user@acme.com",
    "org_slug": "acme-corp",
    "service_slug": "main-app"
  }'

Response - SSO Redirect Required (200 OK)

{
  "method": "redirect",
  "provider": "github",
  "redirect_url": "/auth/github?org=acme-corp&service=main-app"
}

Response - Password Login (200 OK)

{
  "method": "password"
}

Response Fields

Field Type Description
method string "redirect" or "password"
provider string OAuth provider name (when method is redirect)
redirect_url string URL to redirect user to (when method is redirect)

Errors

Status Code Condition
400 BAD_REQUEST Invalid email format
404 NOT_FOUND Organization or service not found

Configuring HRD

Step 1: Verify Domain Ownership

Before enabling HRD for a domain, you must verify ownership:

curl -X POST https://sso.example.com/api/organizations/acme-corp/domains \
  -H "Authorization: Bearer {jwt}" \
  -H "Content-Type: application/json" \
  -d '{
    "domain": "acme.com"
  }'

Response:

{
  "domain": "acme.com",
  "verification_token": "authos-verify=abc123def456",
  "verified": false
}

Add the verification token as a TXT record:

_authos-verify.acme.com TXT "authos-verify=abc123def456"

Step 2: Verify the Domain

curl -X POST https://sso.example.com/api/organizations/acme-corp/domains/acme.com/verify \
  -H "Authorization: Bearer {jwt}"

Step 3: Configure Upstream Provider

curl -X POST https://sso.example.com/api/organizations/acme-corp/upstream-providers \
  -H "Authorization: Bearer {jwt}" \
  -H "Content-Type: application/json" \
  -d '{
    "provider": "saml",
    "name": "Okta SSO",
    "domains": ["acme.com"],
    "config": {
      "idp_metadata_url": "https://acme.okta.com/app/.../sso/saml/metadata",
      "sp_entity_id": "https://sso.example.com/saml/acme-corp"
    }
  }'

Supported Providers

Provider Type Configuration
GitHub OAuth 2.0 Client ID, Client Secret
Google OAuth 2.0 Client ID, Client Secret
Microsoft OAuth 2.0 Client ID, Client Secret, Tenant ID
SAML SAML 2.0 IDP Metadata URL or manual config

SSO Enforcement

When HRD is configured for a domain, you can optionally enforce SSO:

curl -X PATCH https://sso.example.com/api/organizations/acme-corp/upstream-providers/{id} \
  -H "Authorization: Bearer {jwt}" \
  -H "Content-Type: application/json" \
  -d '{
    "enforce_sso": true
  }'

With enforcement enabled:

  • Users with matching email domains must authenticate via SSO
  • Password login is disabled for these users
  • Password reset is disabled for these users

Client Integration

React Example

import { useState } from 'react';

function LoginForm() {
  const [email, setEmail] = useState('');
  const [showPassword, setShowPassword] = useState(false);

  async function handleEmailSubmit(e) {
    e.preventDefault();
    
    const response = await fetch('/api/auth/lookup-email', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        email,
        org_slug: 'acme-corp',
        service_slug: 'main-app'
      })
    });
    
    const result = await response.json();
    
    if (result.method === 'redirect') {
      // Redirect to SSO provider
      window.location.href = result.redirect_url;
    } else {
      // Show password field
      setShowPassword(true);
    }
  }

  return (
    <form onSubmit={handleEmailSubmit}>
      <input
        type="email"
        value={email}
        onChange={(e) => setEmail(e.target.value)}
        placeholder="Enter your email"
      />
      {showPassword && (
        <input type="password" placeholder="Password" />
      )}
      <button type="submit">
        {showPassword ? 'Sign In' : 'Continue'}
      </button>
    </form>
  );
}

Security Considerations

  1. Domain Verification Required - HRD only routes verified domains
  2. No Email Enumeration - Always returns a response regardless of user existence
  3. Rate Limited - Prevents domain probing attacks
  4. HTTPS Required - All HRD endpoints require HTTPS