Beta . Ortha CMS is in public beta. Every plan is free until it ends.
Features Ortha CMS on GitHub

The scripted provider

Identity plugin @orthacms/identity-server@orthacms/identity-admin

Driving the whole SSO handshake with no identity provider to hand.

Documents 0.13.1 Updated Edit this page Report a problem

On this page

@orthacms/identity-provider-fake is a deterministic identity provider: no network, no tenant, no clock skew.

  • Published, and installed in every generated app.
  • Registered by no composition root. It signs in whoever it was scripted to, without anyone authenticating.
  • It really verifies: responses are signed, and complete checks the signature, state and nonce, each with its own SsoVerificationError.

Never in a deployment

Registering it adds a sign-in button that needs no password. Keep it behind a test-only or development-only branch.

Register (tests or local dev only)

import { createFakeSsoProvider } from '@orthacms/identity-provider-fake';

const idp = createFakeSsoProvider({
    label: 'Fake IdP',          // default
    users: [
        { subject: 'idp-ada', email: 'ada@example.com', name: 'Ada', groups: ['cms-editors'] },
        { subject: 'idp-grace', email: 'grace@example.com', emailVerified: false }
    ]
});

IdentityPlugin(config.plugins.identity, {
    sso: {
        providers: process.env.NODE_ENV === 'test' ? [{ name: 'fake', provider: idp }] : []
    }
});

FakeSsoProviderConfig is { users, label?, secret? }. Each user is { subject, email, emailVerified?, name?, groups? }; emailVerified defaults to true. At least one user is required.

Drive it

MemberWhat it does
signInAs(subject)Who the next authorize hands back. Throws for an unknown subject
failNextVerification(reason?)The next complete rejects, once
calls(){ authorize, complete } counts
logoutToken({ sessionId?, subject? })A back-channel logout token it will accept
idp.signInAs('idp-grace');   // unverified address: cannot claim an existing account
idp.failNextVerification();  // next callback lands on /identity/signin?error=sso
expect(idp.calls()).toEqual({ authorize: 1, complete: 1 });

The whole handshake with curl

The fake’s authorize URL points straight back at the callback, so the flow runs with no browser:

API=http://localhost:3000

# 1. Listed
curl -s $API/api/auth/sso
# [{"name":"fake","label":"Fake IdP","kind":"oidc"}]

# 2. Start: sets the attempt cookie, 302s to the callback with a signed code
CALLBACK=$(curl -s -c jar.txt -o /dev/null -w '%{redirect_url}' $API/api/auth/sso/fake/start)

# 3. Callback: completes sign-in, sets orthacms_session, 302s into the admin
curl -si -b jar.txt -c jar.txt "$CALLBACK" | grep -i '^location\|^set-cookie'

# 4. Signed in as the scripted user
curl -s -b jar.txt $API/api/auth/me

Back-channel logout:

# TOKEN = idp.logoutToken({ subject: 'idp-ada' }), taken from your test harness
curl -s -X POST $API/api/auth/sso/fake/backchannel-logout -d "logout_token=$TOKEN"
# {"revoked":1}

Testing the linking rule

A first sign-in may claim an existing account only when the provider says the email is verified. Script emailVerified: false to exercise the refusal. See what a sign-in may do.

It also sends the PKCE challenge, never the verifier, so the conformance kit’s check is meaningful. It is the worked example for writing an SSO provider.