Skip to content

Latest commit

 

History

History
255 lines (199 loc) · 8.95 KB

File metadata and controls

255 lines (199 loc) · 8.95 KB
title Social & Enterprise SSO
description Enable Google sign-in in open source, and extend auth providers through packages.

Social & Enterprise SSO

ObjectStack open source ships two built-in social sign-in implementations, both wired by os serve from deployment env vars:

  • Google OAuth: configure in Setup → Authentication, or from GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET deployment env vars
  • GitHub OAuth: configure from GITHUB_CLIENT_ID and GITHUB_CLIENT_SECRET deployment env vars

Additional providers should be contributed by product or enterprise packages through the auth:configure hook. Those packages can add better-auth socialProviders or OIDC/generic OAuth providers without forking @objectstack/plugin-auth.

The Studio login and registration pages automatically render Continue with ... buttons for every enabled provider returned by /api/v1/auth/config.


Social Providers

Google

  1. Go to Google Cloud ConsoleAPIs & ServicesCredentials.
  2. Click Create CredentialsOAuth 2.0 Client IDWeb application.
  3. Add an Authorized redirect URI:
    https://<your-domain>/api/v1/auth/callback/google
    
    For local development: http://localhost:3000/api/v1/auth/callback/google
  4. Copy the Client ID and Client Secret.

Then either save the values in Setup → Authentication → Social sign-in or provide them as deployment environment variables:

GOOGLE_CLIENT_ID=your-google-client-id
GOOGLE_CLIENT_SECRET=your-google-client-secret

# Optional settings env override. UI settings are lower precedence than env.
# OS_AUTH_GOOGLE_ENABLED=false

GitHub

  1. Go to GitHub Developer SettingsOAuth AppsNew OAuth App.
  2. Set Authorization callback URL:
    https://<your-domain>/api/v1/auth/callback/github
    
  3. Copy the Client ID and generate a Client Secret.

Provide them as deployment environment variables:

GITHUB_CLIENT_ID=your-github-client-id
GITHUB_CLIENT_SECRET=your-github-client-secret

Extension Packages

The providers below are examples for enterprise or product packages, not built-in open-source settings. A package can register them by listening to auth:configure and mutating the draft auth config.

The env-var names shown below (e.g. MICROSOFT_CLIENT_ID, APPLE_CLIENT_ID) are illustrative for an extension package's own reader code — unlike GOOGLE_* and GITHUB_*, the framework does not read them out of the box, so an extension must wire them in its auth:configure handler.

Microsoft (Azure AD / Entra ID)

  1. Go to Azure PortalAzure Active DirectoryApp registrationsNew registration.
  2. Add a redirect URI (Web):
    https://<your-domain>/api/v1/auth/callback/microsoft
    
  3. Under Certificates & secrets, create a new client secret.
MICROSOFT_CLIENT_ID=your-azure-app-client-id
MICROSOFT_CLIENT_SECRET=your-azure-client-secret

# Optional: restrict to a single tenant (default: "common" — all Microsoft accounts)
# MICROSOFT_TENANT_ID=your-tenant-id

Apple

  1. Go to Apple Developer ConsoleCertificates, IDs & ProfilesIdentifiers → register a Services ID.
  2. Enable Sign In with Apple and configure the redirect URL:
    https://<your-domain>/api/v1/auth/callback/apple
    
  3. Generate a private key under Keys.
APPLE_CLIENT_ID=your-apple-services-id
APPLE_CLIENT_SECRET=your-apple-private-key-jwt

Apple requires the client secret to be a signed JWT derived from the private key. See better-auth Apple docs for details.


Enterprise SSO (OIDC) Extension Example

Enterprise packages can pass oidcProviders into @objectstack/plugin-auth or contribute them through auth:configure. The open-source package does not ship a generic OIDC settings UI.

Per-environment external IdP (ADR-0069). Recent releases add a per-environment external-IdP path built on @better-auth/sso (a generic OIDC relying party) and surface an sso flag in the public /auth/config (features.sso) so a client can show an enterprise-login button when SSO is configured. The oidcProviders extension below remains the in-process path.

Quick start — Okta

const oidcProviders = [
  {
    "providerId": "okta",
    "name": "Okta",
    "discoveryUrl": "https://your-org.okta.com/.well-known/openid-configuration",
    "clientId": "your-okta-client-id",
    "clientSecret": "your-okta-client-secret",
    "scopes": ["openid", "email", "profile"]
  }
];

Quick start — Azure AD (OIDC)

const oidcProviders = [
  {
    "providerId": "azure-ad",
    "name": "Azure AD",
    "discoveryUrl": "https://login.microsoftonline.com/<tenant-id>/v2.0/.well-known/openid-configuration",
    "clientId": "your-azure-client-id",
    "clientSecret": "your-azure-client-secret"
  }
];

Quick start — Keycloak

const oidcProviders = [
  {
    "providerId": "keycloak",
    "name": "Keycloak",
    "discoveryUrl": "https://keycloak.example.com/realms/your-realm/.well-known/openid-configuration",
    "clientId": "your-client-id",
    "clientSecret": "your-client-secret",
    "pkce": true
  }
];

Multiple enterprise providers

const oidcProviders = [
  {
    "providerId": "okta",
    "name": "Okta SSO",
    "discoveryUrl": "https://your-org.okta.com/.well-known/openid-configuration",
    "clientId": "...",
    "clientSecret": "..."
  },
  {
    "providerId": "azure-ad",
    "name": "Microsoft SSO",
    "discoveryUrl": "https://login.microsoftonline.com/<tenant>/v2.0/.well-known/openid-configuration",
    "clientId": "...",
    "clientSecret": "..."
  }
];

OIDC provider fields

Field Required Description
providerId Unique identifier used internally (e.g. okta, azure-ad)
name Display name shown on the button (defaults to providerId)
discoveryUrl ✅* OIDC discovery URL — auto-fetches all endpoints
authorizationUrl ✅* OAuth2 authorization endpoint (if no discoveryUrl)
tokenUrl ✅* OAuth2 token endpoint (if no discoveryUrl)
userInfoUrl OAuth2 userinfo endpoint
issuer Expected issuer for token validation
clientId OAuth2 client ID
clientSecret OAuth2 client secret
scopes Requested scopes (default: openid email profile)
pkce Enable PKCE — recommended for public clients

*Either discoveryUrl or authorizationUrl + tokenUrl must be provided.


Verify configuration

Restart the server (pnpm dev), then:

curl http://localhost:3000/api/v1/auth/config

Expected response (abbreviated — getPublicConfig() also returns disableSignUp/requireEmailVerification on emailPassword and additional features keys such as multiOrgEnabled, oidcProvider, deviceAuthorization, and admin):

{
  "emailPassword": { "enabled": true },
  "socialProviders": [
    { "id": "google", "name": "Google", "enabled": true, "type": "social" },
    { "id": "github", "name": "GitHub", "enabled": true, "type": "social" },
    { "id": "okta",   "name": "Okta SSO", "enabled": true, "type": "oidc" }
  ],
  "features": { "twoFactor": false, "passkeys": false, "magicLink": false, "organization": true }
}

The Studio /login and /register pages will now show a button for each enabled provider.


OAuth flow

Social providers (Google, GitHub, Microsoft, Apple):

  1. User clicks Continue with Google (or similar).
  2. Client calls POST /api/v1/auth/sign-in/social with { provider: "google", callbackURL }.
  3. Browser redirects to the provider's consent screen.
  4. Provider redirects to /api/v1/auth/callback/google.
  5. better-auth creates a session and redirects to callbackURL.

OIDC/enterprise providers:

  1. User clicks Continue with Okta SSO.
  2. Client calls POST /api/v1/auth/sign-in/oauth2 with { providerId: "okta", callbackURL }.
  3. Browser redirects to the provider's authorization endpoint.
  4. Provider redirects back; better-auth validates the OIDC token and creates a session.

Notes

  • OS_AUTH_SECRET must be set to a random string in production (a long random value of 32+ characters is recommended). AUTH_SECRET and BETTER_AUTH_SECRET are accepted as deprecated legacy aliases and emit a deprecation warning. If no secret is set, the auth plugin is skipped in production.
  • OS_AUTH_URL (or OS_BASE_URL as a fallback) must match the domain registered with each provider; it determines the base URL used to build OAuth callback URLs.
  • Never commit client secrets to source control — use a secrets manager in production.
  • The redirect URI registered with each provider must match exactly: https://<your-domain>/api/v1/auth/callback/<provider-id>.