// getting started

SSO.so Docs

SSO.so is a self-hosted Single Sign-On service built on Keycloak 26, running on Ubuntu 24.04 behind a Caddy reverse proxy. It provides OpenID Connect, OAuth 2.0, and SAML 2.0 authentication for all your products from a single identity server at sso.sso.so.

Info

The admin console is available at sso.sso.so/admin. Keep that URL out of your public docs — admin access should be restricted by IP or VPN where possible.

Component Details
Identity serverKeycloak 26 on Ubuntu 24.04
Public URLhttps://sso.sso.so
Reverse proxyCaddy (auto TLS via Let's Encrypt)
DatabasePostgreSQL 16 (localhost only)
ProtocolsOIDC, OAuth 2.0, SAML 2.0

Quick start

Get your first app authenticating against SSO.so in three steps.

1

Fetch the discovery document

Every OIDC library needs this URL — it auto-configures all endpoints.

2

Register your client in the admin console

Go to your realm → Clients → Create. Copy the client ID and secret.

3

Configure your app's OIDC library

Point it at the discovery document and add your client credentials.

Discovery document URL
https://sso.sso.so/realms/{your-realm}/.well-known/openid-configuration
Example — Node.js with openid-client
import { Issuer } from 'openid-client';

const issuer = await Issuer.discover(
  'https://sso.sso.so/realms/myproducts'
);

const client = new issuer.Client({
  client_id:     'myapp',
  client_secret: 'your-client-secret',
  redirect_uris: ['https://myapp.example.com/auth/callback'],
  response_types: ['code'],
});

OpenID Connect

SSO.so speaks standard OIDC. Any library that supports OIDC discovery will work — openid-client (Node), authlib (Python), spring-security-oauth2 (Java), league/oauth2-client (PHP), etc.

Endpoints

Replace myproducts with your actual realm name throughout.

EndpointURL
Discovery/realms/myproducts/.well-known/openid-configuration
Authorization/realms/myproducts/protocol/openid-connect/auth
Token/realms/myproducts/protocol/openid-connect/token
Userinfo/realms/myproducts/protocol/openid-connect/userinfo
JWKS/realms/myproducts/protocol/openid-connect/certs
Logout/realms/myproducts/protocol/openid-connect/logout

Token reference

Keycloak issues standard JWT access tokens. Verify them locally using the JWKS endpoint — never send them to an external service for validation.

Decoded access token payload (example)
{
  "iss": "https://sso.sso.so/realms/myproducts",
  "sub": "a1b2c3d4-e5f6-...",
  "aud": "myapp",
  "exp": 1743700000,
  "iat": 1743699700,
  "email": "user@example.com",
  "email_verified": true,
  "realm_access": { "roles": ["app-user"] },
  "preferred_username": "johndoe"
}

PKCE flow

All public clients (SPAs, mobile apps) must use PKCE. Confidential clients (server-side apps) should use it too — it's enabled by default on all clients registered through SSO.so.

Authorization request with PKCE
# 1. Generate code verifier (random 43-128 char string)
code_verifier=$(openssl rand -base64 32 | tr -d '=+/' | cut -c1-43)

# 2. Derive code challenge (S256)
code_challenge=$(echo -n "$code_verifier" | sha256sum | cut -d' ' -f1 | xxd -r -p | base64 | tr -d '=' | tr '+/' '-_')

# 3. Authorization URL
https://sso.sso.so/realms/myproducts/protocol/openid-connect/auth
  ?client_id=myapp
  &response_type=code
  &redirect_uri=https://myapp.example.com/callback
  &scope=openid profile email
  &code_challenge=$code_challenge
  &code_challenge_method=S256
  &state=$(openssl rand -hex 16)
Important

Always validate the state parameter on return to prevent CSRF. Never store the code verifier in localStorage — use sessionStorage or server-side session only.

Registering clients

Each application that uses SSO.so needs its own client registration. Go to Admin → your realm → Clients → Create client.

SettingRecommended value
Client typeOpenID Connect
Client authenticationOn (confidential) for server apps; Off (public) for SPAs
Standard flowOn
Direct access grantsOff (unless you need resource owner password flow)
Valid redirect URIsExact match — never use * wildcards in production
PKCE methodS256 (set in Client → Advanced → PKCE)

Email / SMTP

Keycloak sends emails for account verification, password reset, and MFA enrollment. Configure your SMTP provider in Realm Settings → Email.

Example — using Brevo (formerly Sendinblue)
Host:        smtp-relay.brevo.com
Port:        587
Encryption:  STARTTLS
Auth:        On
Username:    your@email.com
Password:    your-brevo-smtp-key

From:        noreply@sso.so
From display: SSO.so Identity
Note

Click Test connection after saving. Keycloak will send a test email to the admin address. If it fails, check that port 587 is open outbound on your VPS — some providers block it by default.

MFA setup

Enable TOTP (Google Authenticator, Authy) at the realm level under Authentication → Required Actions → Configure OTP → Default On. Users will be prompted to enroll on next login.

Brute force protection

Already configured in your realm JSON import. Verify it's active at Realm Settings → Security Defenses → Brute Force Detection. The defaults are: 10 failures → 60 second lockout, incrementing up to 15 minutes maximum.

Session policy

SettingValueWhere
SSO session idle30 minutesRealm Settings → Sessions
SSO session max10 hoursRealm Settings → Sessions
Access token lifespan5 minutesRealm Settings → Tokens
Refresh token lifespanTied to SSO session maxInherited