~35 min read · updated 2026-05-17

Demo credentials + SCIM provisioning

How the student@comptech.com user gets provisioned via WSO2 IS's SCIM2 API, a single /credentials.html page that's the source of truth for every demo login, and one workaround for the SCIM/admin-console permission gap. Companion commit bf2e1e35 in the insurance-app repo.

Two portals, both gated by OIDC against WSO2 IS, both expecting a real human user to log in. Up to this point the curriculum has been silent on which user — every “Verify” section ended with “open in a browser” and waved at credentials. This chapter fills the gap.

The deliverable is two things: a script-driven SCIM provisioning of one demo user (student@comptech.com / Student@1234) and a single /credentials.html page hosted by Liberty that lists every login the demo exposes. The whole thing is ~35 minutes of work and exists because handing a fresh student “the credentials” turned out to be a multi-page email otherwise.

Companion commit: bf2e1e35 in insurance-app.

SCIM2 — provision a user without the IS console

WSO2 IS exposes a SCIM2 API at /scim2/Users. It accepts a standard SCIM JSON payload and creates a user under the primary userstore in one POST. Compared to clicking through Console → User Management → Add User, it’s:

  • Idempotent (with a delete-then-create wrapper if needed).
  • Scriptable for the SETUP.md runbook.
  • Auditable as a single line in version control rather than five console clicks no one will reproduce.
curl -k -sS -X POST -u admin:admin \
  https://localhost:9444/scim2/Users \
  -H 'Content-Type: application/scim+json' \
  -d '{
    "schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"],
    "userName": "student@comptech.com",
    "password": "Student@1234",
    "emails": [{ "primary": true, "value": "student@comptech.com" }],
    "name": { "givenName": "Demo", "familyName": "Student" }
  }' | jq .

The response includes the user’s id (a UUID). Save it; later steps need it to add the user to the admin role and the admin Group.

Role + Group assignment

A bare SCIM-created user can log into the customer portal and the agent dashboard but cannot open the WSO2 admin consoles (IS Console / Carbon, APIM Publisher / Devportal / Admin). The permission model splits “can-authenticate” from “can-administer.” To get partial admin access:

USER_ID=<from previous SCIM POST>

# 1) Add to the organization-level admin role
curl -k -sS -X PATCH -u admin:admin \
  https://localhost:9444/scim2/Roles/{admin-role-id} \
  -H 'Content-Type: application/scim+json' \
  -d "{
    \"schemas\":[\"urn:ietf:params:scim:api:messages:2.0:PatchOp\"],
    \"Operations\":[{
      \"op\":\"add\",
      \"path\":\"users\",
      \"value\":[{\"value\":\"$USER_ID\"}]
    }]
  }"

# 2) Add to the admin Group (carries Administrator application role)
curl -k -sS -X PATCH -u admin:admin \
  https://localhost:9444/scim2/Groups/{admin-group-id} \
  -H 'Content-Type: application/scim+json' \
  -d "{
    \"schemas\":[\"urn:ietf:params:scim:api:messages:2.0:PatchOp\"],
    \"Operations\":[{
      \"op\":\"add\",
      \"path\":\"members\",
      \"value\":[{\"value\":\"$USER_ID\"}]
    }]
  }"

Now student@comptech.com can also reach My Account (https://is.insurance-app.comptech-lab.com/myaccount) and change its own profile. The IS Console + APIM admin consoles still reject it.

The gap: SCIM-created admins can’t open admin consoles

This is the workaround-worth-knowing-about. WSO2 IS Console and APIM Publisher / Devportal / Admin all key their access checks against Carbon-internal role memberships that SCIM2 does not currently expose through /scim2/Users or /scim2/Groups. A user created entirely via SCIM — even one added to every role SCIM can see — still gets a 403 when they try /console or /publisher.

Two real options, both deferred to a future slice:

  • Federate APIM with IS as a key manager so the APIM admin consoles consume IS users directly.
  • Add Carbon-internal admin role membership via the SOAP UserAdmin API (/services/UserAdmin?wsdl). It’s the legacy interface that predates SCIM2; it can write the role tables the new admin consoles read.

For the demo, the workaround is the one documented on the credentials page: use admin/admin for the WSO2 admin consoles, use student@comptech.com for everything customer-facing. Two logins, clearly labeled, no surprise 403s for the student.

The /credentials.html page

The Liberty webapp gains a tenth static page that lists every login the demo exposes — one per surface, with the actual URL and the credentials inline. It’s a single HTML file, served from src/main/webapp/credentials.html alongside the other tour pages.

The structure mirrors the audiences:

SectionWho it’s forCredentials
Portal userThe customer + agent portals (real OIDC)student@comptech.com / Student@1234
WSO2 adminIS Console, Carbon, APIM Publisher / Devportal / Adminadmin / admin
Object storageMinIO consoleminioadmin / minioadmin
SigNozFirst-launch setup; no credentials(set on first signin)
OtherAdminer, Kafka UI, RedisInsight, Mailpitno auth (lab is intentionally permissive)

Each row has the canonical URL hyperlinked and a short note about what the surface is for. The “intentionally permissive” callout matters — students often poke at things and the lab WANTS them to. Do not run this configuration anywhere real.

The nav of /index.html gains a Credentials link so the page is one click from the tour landing, and the live-portals callout on the home page now points students at the credentials sheet before they ever try to sign in.

Verify

# SCIM provisioning is in place — the user exists
curl -k -sS -u admin:admin \
  'https://localhost:9444/scim2/Users?filter=userName+eq+student@comptech.com' \
  | jq '.Resources[0].userName'
# "student@comptech.com"

# The customer portal accepts the user via OIDC
# (manual: click "Sign in" on https://my.insurance-app.comptech-lab.com,
#  enter student@comptech.com / Student@1234, land back signed in)

# /credentials.html is served and reachable
curl -sI https://app.insurance-app.comptech-lab.com/credentials.html | head -1
# HTTP/2 200

The page is the single artifact you hand to a student. Bookmark it, print it, embed it in onboarding — it’s the URL that ends every “how do I sign into X?” question.

What you have

  • A scripted SCIM2 provisioning of one demo user, added to the admin role + admin Group.
  • A documented workaround for the SCIM/admin-console permission gap (use admin/admin for the WSO2 admin surfaces).
  • A single /credentials.html page that’s the source of truth for every demo login.
  • Honest documentation that the lab is intentionally permissive — the credentials are demo-grade, not production-grade.

One more cross-cutting chapter on hardening the earlier slices and the track is done.

Next: 30 — Hardening pass on the original 14 slices →