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: {auth_method: "upstream", connection_id: "..."}
Client->>AuthOS: GET /auth/github?org=acme&service=app&connection_id=...
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 | 1 request/second (Burst: 20) |
| Idempotent | Yes |
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
email |
string |
Yes | User’s email address |
Example Request
curl -X POST https://sso.example.com/api/auth/lookup-email \
-H "Content-Type: application/json" \
-d '{
"email": "user@acme.com"
}'
Response - Upstream SSO Required (200 OK)
{
"auth_method": "upstream",
"connection_id": "con_okta_123",
"provider_name": "Acme Okta",
"domain_verified": true
}
Response - Fallback to Password/OAuth (200 OK)
{
"auth_method": "password",
"connection_id": null,
"provider_name": null,
"domain_verified": true
}
Response Fields
| Field | Type | Description |
|---|---|---|
auth_method |
string |
"upstream", "password", or "oauth" |
connection_id |
string |
The ID of the upstream connection to use |
provider_name |
string |
Display name of the provider |
domain_verified |
boolean |
Whether the domain ownership has been verified |
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 |
| 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.auth_method === 'upstream') {
// Redirect to SSO provider with connection_id
window.location.href = `/auth/github?org=acme-corp&service=main-app&connection_id=${result.connection_id}`;
} else {
// Show password field or default OAuth
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
- Domain Verification Required - HRD only routes verified domains
- No Email Enumeration - Always returns a response regardless of user existence
- Rate Limited - Prevents domain probing attacks
- HTTPS Required - All HRD endpoints require HTTPS