Live demo

See OpsAPI working end to end

A real OpsAPI deployment with every app switched on and filled with sample data, single sign-on through a SAML identity provider, and five apps in five languages (Java, PHP, Python, Rust and Go) that share one sign-in. Look around the dashboard with a read-only account or SSO, then sign in to the apps.

Demo login

Use this on the dashboard, or on OpsAPI's sign-in page when an app sends you there.

Email
demo@opsapi.org
Password
OpsAPI-Demo-2026!

Read-only, and reset every 30 minutes. Every page opens, every change is refused. The account lives in a showcase workspace whose other users are fictional, so you never see a real person's details.

What's running

HostWhat it is
showcase.demo.opsapi.orgAdmin dashboard: every app, with sample data
showcase-api.demo.opsapi.orgOpsAPI API behind it (every module on)
saml-idp.demo.opsapi.orgDemo SAML identity provider (Mock SAML)
identity.demo.opsapi.orgOpsAPI sign-in for the five apps
hello-java.demo.opsapi.orgJava demo app
hello-php.demo.opsapi.orgPHP demo app
hello-python.demo.opsapi.orgPython demo app
hello-rust.demo.opsapi.orgRust demo app
hello-go.demo.opsapi.orgGo demo app

How the demo fits together

The live demo: five apps and a dashboard sharing one OpsAPI identity service and two workspaceshello-javahello-phphello-pythonhello-rusthello-goAdmin dashboardNext.js/auth/loginOpsAPI identitysign-in, 2FA, Googleusers, roles, workspacescore_only buildPostgreSQLown databaseWORKSPACE: SHOWCASEdemo@opsapi.org (read-only)6 fictional sample usersno emailed codereset every 30 minutesWORKSPACE: DEMOpeople who sign in withtheir own Google accountprivate: the demo logincan't see it
All three front ends use the same identity service. The demo login and its sample users live in one workspace; real Google sign-ins land in another, so the public login can't see them.

Under the hood

How each demo signs you in

Four ways in, all ending the same way: OpsAPI issues a short-lived JWT for one workspace, and every API call is checked against that workspace's roles. The diagrams follow the real requests, step by step.

The live demos: which front end uses which OpsAPI, and which sign-in methods each offersFRONT ENDSOPSAPI DEPLOYMENTSWHO VOUCHES FOR THE USERFull dashboardshowcase.demo.opsapi.orgevery app, sample datacurl / your scriptsBearer JWT from /auth/loginFive appshello-java, php, python,rust, goIdentity dashboarddashboard.demo.opsapi.orgshowcase-apiPROJECT_CODE=allworkspace: showcaseown Postgresidentity.demoPROJECT_CODE=core_onlyhosted sign-in pageworkspaces: showcase, demoPassword (+ code)OpsAPI itselfSAML IdPsaml-idp.demo.opsapi.orgPassword (+ code)OpsAPI itselfGoogleOAuth 2.0 / OIDCSSOseparate deployments,separate databases
Two OpsAPI deployments back the demos. The full dashboard signs in with a password or SAML; the five apps use OpsAPI's hosted sign-in page with a password or Google.
MethodWhere to try itWho checks the userWhat you get
Email and passwordFull dashboard, demo loginOpsAPI (bcrypt, optional emailed code)JWT + refresh cookie
GoogleThe five apps' sign-in pageGoogle, verified email onlyJWT on the callback
Login with OpsAPIThe five appsOpsAPI hosted page; app checks a nonce, then /auth/meApp session + JWT
SAML single sign-onFull dashboard, Sign in with SSOThe workspace's IdP; OpsAPI verifies the signatureOne-time code → JWT

Flow 1 · showcase.demo.opsapi.org, with the demo login

Email and password (+ emailed code)

The dashboard posts the password to OpsAPI. OpsAPI checks it, asks for an emailed code when the workspace requires one, and returns a short-lived JWT plus a refresh token in an HttpOnly cookie. Every API call then carries the JWT and the workspace, and the role decides read or write.

Email and password (+ emailed code): step-by-step sequenceBrowserthe visitorDashboardNext.jsOpsAPIshowcase-apiEmailonly if required1Email + passworddemo@opsapi.org2POST /auth/login10/min per IP · lockout per account3bcrypt check · account activeusers table4Does a workspace require a code?showcase: no · platform admins: always5Six-digit code (when required)stored hashed, 5/min6{ requires_2fa, session_token }7POST /auth/2fa/verify{ session_token, code }8JWT + refresh_token cookieHttpOnly, Secure9GET /api/v2/…Authorization: Bearer JWT · X-Namespace-Slug: showcase10JWT · membership · module.actionviewer role = read on every module11200 for reads · 403 for any change12POST /auth/refresh when the JWT expirescookie in, new JWT out
Solid arrows are requests, dashed arrows redirects and responses, green the result that matters. Boxes on a line are what that party checks or does.
ConcernHow it works
Where the password livesOnly OpsAPI sees it; bcrypt hashes in users
Second factorEmailed code, per workspace setting (off in showcase, nobody reads the demo inbox)
SessionJWT in the Authorization header; refresh token only in an HttpOnly cookie
What the demo login can doRead everything in showcase; every change is refused with 403

Try it: Sign in with demo@opsapi.org

Flow 2 · the five apps' sign-in page (identity.demo.opsapi.org)

Google sign-in (OAuth 2.0 / OpenID Connect)

OpsAPI runs the whole OAuth exchange: the dashboard only sends the browser to /auth/google. A nonce rides in both the state and a cookie so nobody can finish their own Google sign-in in your browser. Only an email Google has verified can sign in or be linked.

Google sign-in (OAuth 2.0 / OpenID Connect): step-by-step sequenceBrowserthe visitorDashboardor the hosted pageOpsAPIidentityGoogleaccounts.google.com1Continue with Google2GET /auth/google?frontend_url=<origin>&from=<path>3Random nonce → cookie and stateopsapi_oauth_nonce, 10 min4302 to Google consentclient_id · redirect_uri · openid profile email · state5Pick account, consentGoogle's own 2-step if on6GET /auth/google/callback?code=…&state=…7state nonce = cookie nonce?else 400: login CSRF8Swap code for access tokenserver to server, client secret9GET userinfoemail · verified_email · name10Verified? find or create user · join workspacenew users join the sign-up workspace11/auth/callback?token=JWTtrusted origins only · + refresh cookie12Adopt session, strip token from the URL
Solid arrows are requests, dashed arrows redirects and responses, green the result that matters. Boxes on a line are what that party checks or does.
ConcernHow it works
Who talks to GoogleOnly OpsAPI; apps never hold a Google client secret
Login CSRFNonce in state must equal the nonce cookie
Account linkingBy email, and only when Google says the email is verified
Where tokens may goOnly origins on the CORS / allowed-origins list

Try it: Log in to the Java app, then Continue with Google

Flow 3 · hello-java, hello-php, hello-python, hello-rust, hello-go

Login with OpsAPI (hosted sign-in for your apps)

Your app never sees a password. It sends the browser to OpsAPI's hosted page with a nonce, gets a JWT back on its callback, checks the nonce, and asks /auth/me who the user is. A second app finds the OpsAPI session already there and gets its token without a prompt.

Login with OpsAPI (hosted sign-in for your apps): step-by-step sequenceBrowserthe visitorYour apphello-java …OpsAPIidentity.demoGoogleoptional1Log in2Random nonce in the session3Redirect to the hosted page/auth/signin?frontend_url=<app>&from=<nonce>4Already signed in to OpsAPI? skip the formsilent sign-in for the 2nd, 3rd … app5Password (+ code) or Googlesame checks as the two flows above6Origin trusted? sign the JWT7/auth/callback?token=JWT&redirect=<nonce>8nonce = session nonce?else 400, a forged link9GET /auth/meAuthorization: Bearer JWT10user · workspace · role11New session id, own cookie12Log out everywhere/auth/signout
Solid arrows are requests, dashed arrows redirects and responses, green the result that matters. Boxes on a line are what that party checks or does.
ConcernHow it works
What the app storesIts own session and the JWT; never a password
How it checks the tokenOne call to /auth/me; the signing key never leaves OpsAPI
Forged callback linksRefused: the nonce must match the session
Single sign-on across appsOne OpsAPI session, a fresh token per app

Try it: Open the Java app

Flow 4 · showcase.demo.opsapi.org → Sign in with SSO, with the demo IdP

SAML 2.0 single sign-on

The workspace's own identity provider vouches for the user. OpsAPI sends a SAML AuthnRequest, the IdP posts back a signed response, and OpsAPI checks the signature against the certificate saved for that workspace before anything else. The dashboard then swaps a one-time code for the JWT, so the token never appears in a URL.

SAML 2.0 single sign-on: step-by-step sequenceBrowserthe visitorDashboardlogin pageOpsAPIservice providerIdentity providersaml-idp.demo1Sign in with SSOvisitor@example.com2GET /auth/saml/discover?email=… → provider for example.com3GET /auth/saml/:id/login4Request ID → signed state cookieHMAC, 10 min5302 with SAMLRequestHTTP-Redirect: deflate + base646User signs in (MFA at the IdP)response signed RSA-SHA2567POST /auth/saml/:id/acsSAMLResponse, auto-submitted form8Signature by the saved cert · one AssertionIssuer · Audience · Recipient · time · InResponseTo9Assertion ID unused · email domain allowednot in another workspace · join as viewer10/auth/callback?saml_code=…one-time, 2 minutes11POST /auth/saml/exchange{ code } – single use12JWT for the showcase workspace
Solid arrows are requests, dashed arrows redirects and responses, green the result that matters. Boxes on a line are what that party checks or does.
ConcernHow it works
TrustThe IdP's certificate saved per workspace; certificates inside messages are ignored
RefusedTampered, wrapped, unsigned, replayed, expired or misaddressed responses; DTDs; SHA-1
Scope of trustAn IdP vouches for its own workspace and email domains only
Demo IdPMock SAML: no password, so only the read-only showcase trusts it

Try it: Sign in with SSO as visitor@example.com

Tour the admin dashboard

  1. Open showcase.demo.opsapi.org and sign in with the demo login. No emailed code is needed in this workspace.
  2. Apps: the catalog of every module this deployment runs; open CRM, invoices, projects, the shop, care home, hiring and more, each with sample records.
  3. Users: see the sample team and each person's role: owner, admin, developer, member.
  4. Roles: open a role to see its module.action permissions, and the read-only viewer role you're signed in with.
  5. Workspace and settings: see how a tenant is configured, including whether members need an emailed code, and the Single sign-on page with the workspace's SAML identity provider.
  6. Try to change something. The API refuses it with 403, which is what a viewer should get.

Sign in to the apps

  1. Open hello-java and choose “Login with OpsAPI”. The app sends you to OpsAPI's sign-in page.
  2. Sign in with the demo login, or with your own Google account. Google sign-ins join the private demo workspace as a member.
  3. You come back signed in. The app asked OpsAPI who you are with one call to /auth/me and shows your workspace and role.
  4. Open any of the others (PHP, Python, Rust, Go) and log in there too: same account, no second prompt.
  5. Sign out everywhere from either app; the next sign-in asks again.

Sign in with SAML single sign-on

The showcase workspace is connected to a demo SAML 2.0 identity provider. It stands in for your company's Okta, Entra ID or Google Workspace, but asks for no password: any address at example.com or example.org works.

  1. Open the dashboard sign-in page and choose Sign in with SSO.
  2. Enter a work email such as visitor@example.com and press Continue. OpsAPI finds the workspace's provider from the domain.
  3. You land on the demo IdP at saml-idp.demo.opsapi.org. Press Sign In.
  4. The IdP posts a signed SAML response back to OpsAPI, which checks the signature, audience, time window and request, then signs you in.
  5. You are in the showcase as a read-only viewer, under the address you typed. Open Single sign-on in the sidebar to see how the provider is set up.

Same rules as production. The demo IdP is trusted by the showcase workspace only, for its two domains only. A tampered, replayed, unsigned or misaddressed response is refused, and so is an account that belongs to another workspace. Details in the SAML technote.

SAML endpoints

EndpointWhat it does
GET /auth/saml/discover?email=Finds the provider for an email domain
GET /auth/saml/:id/metadataService-provider metadata to give your IdP
GET /auth/saml/:id/loginStarts sign-in: redirects to the IdP
POST /auth/saml/:id/acsReceives the signed response, signs you in
/api/v2/sso/saml/providersWorkspace owners add and edit providers
# which provider handles example.com?
curl -s "https://showcase-api.demo.opsapi.org/auth/saml/discover?email=visitor@example.com"

# the demo IdP's metadata (entity ID, sign-in URL, certificate)
curl -s https://saml-idp.demo.opsapi.org/api/saml/metadata

To connect your own IdP, sign in to your workspace, open Workspace → Single sign-on, paste the IdP metadata, then give the IdP the Entity ID and ACS URL shown there.

The five apps

AppStackSigned-in pagesCode
hello-javaSpring Boot/api/secure/me, /api/secure/resourcesource
hello-phpPHP 8.3/dashboardsource
hello-pythonPython 3.13, standard library/dashboardsource
hello-rustRust, tiny_http + ureq/dashboardsource
hello-goGo, standard library/dashboardsource

All five use the same routes (/login, /auth/callback, /logout), check the token with GET /auth/me, and refuse a forged callback with 400.

Each app keeps a random nonce in its session when you click log in and only accepts the token back if the nonce matches, so a link carrying someone else's token can't sign you in. The full sequence is in the sign-in flow technote, and how the public login is kept safe is in building a safe public demo login.

Try the API directly

# sign in as the demo account (form-encoded)
curl -s -X POST https://identity.demo.opsapi.org/auth/login \
  --data-urlencode username=demo@opsapi.org \
  --data-urlencode 'password=OpsAPI-Demo-2026!'

# who am I?
curl -s https://identity.demo.opsapi.org/auth/me -H "Authorization: Bearer $TOKEN"

# the showcase team (read access)
curl -s https://identity.demo.opsapi.org/api/v2/namespace/members \
  -H "Authorization: Bearer $TOKEN" -H "X-Namespace-Slug: showcase"

# a change is refused (403)
curl -s -X POST https://identity.demo.opsapi.org/api/v2/users -H "Authorization: Bearer $TOKEN" \
  -H "X-Namespace-Slug: showcase" --data-urlencode email=new@example.com

identity.demo.opsapi.org runs a minimal core_only build (sign-in, users, workspaces and roles) for the five apps; it has its own dashboard at dashboard.demo.opsapi.org. Every business module, with sample data, is on the showcase.