Silicon IAM frontend
The first official v1 frontend provides application permission consent, organization selection, batch login, and application bundles. See the batch login guide and bundle guide.
The SolidJS frontend has two entry points in one codebase:
- Main IAM console:
/for applications, organizations, directory, governance, testing-environment administration, profile and sessions. - IAM authentication:
/loginand/signup, with/login?app_id=org%3Eapp&redirect_uri=…for application login. Apps must not supply organization scope; users choose it in IAM. Configure a separate auth origin when hosting.
The app talks only to its same-origin session gateway. This is not a static-only website: deploy the gateway with the assets. Source lives in frontend/ in the IAM repository; run the commands below there. Run the v1 backend with its complete production migrations, testing overlay, and runtime grants. See organization consent.
Local development
Requires Node 24 and npm. Install with npm ci; run npm run dev (port 4310). Configure .env.development.local first:
API_UPSTREAM=http://127.0.0.1:4320
CONSOLE_ORIGIN=http://127.0.0.1:4310
AUTH_ORIGIN=http://127.0.0.1:4310
DISPLAY_ENVIRONMENT=Local testing
Use an isolated local IAM API, its official migrations, and runtime database roles. Do not point manual test runs at production. Local development without a configured cookie key generates an ephemeral key: restarting the dev server signs out existing browser sessions. A fixed, random development-only key avoids that; never reuse a QA key in production.
The local API may expose local_otp only with explicit local-provider settings. The UI renders these codes only on a loopback hostname. Ordinary local-provider OTPs are random; 000000 is reserved for key-selected IAM testing environments.
npm run check
npm run build
# After providing server env vars, serve the actual built app + gateway:
npm start
Hosting
Nothing is published automatically. Build outputs:
dist/client/: browser assets, including official IAM handoff-page styles/fonts.dist/server/index.js: platform-neutral Worker-style{ fetch(request, env) }gateway. BindASSETS.fetchto the asset directory, including/index.htmlfallback.dist/server/node.js: standalone Node server for a reverse proxy/container..vercel/output/: Vercel Build Output API v3 package, generated bynpm run build:vercel. Includes one Node 24 function and its browser assets; every route goes through the same secure gateway.
Copy .env.example to an ignored environment file, supply a fresh 32-byte base64url SESSION_COOKIE_KEY, and use your hosting platform’s secret manager. Keep the same key across replicas and restarts. Changing it invalidates frontend sessions. Node can load an environment file with node --env-file=.env dist/server/node.js. Never bundle environment files into public assets.
For the intended two domains:
API_UPSTREAM=https://backend.iam.teamofsilicons.com
CONSOLE_ORIGIN=https://iam.teamofsilicons.com
AUTH_ORIGIN=https://auth.iam.teamofsilicons.com
COOKIE_DOMAIN=iam.teamofsilicons.com
Terminate HTTPS at a trusted reverse proxy, preserve the exact configured Host, proxy all paths to this server, and exclude request bodies, cookies, authorization headers, SLTs, callback URLs, and setup URLs from access/analytics logs. Do not put any untrusted app under the shared cookie domain. Both frontend origins use the same deployment configuration and encryption key.
Vercel deployment
The silicon-iam-frontend project uses the existing Vercel domain setup. Set the production variables above plus DISPLAY_ENVIRONMENT=Production; create SESSION_COOKIE_KEY as a Sensitive environment variable. Never pull the production key into a development environment or pass it as a build argument.
npm ci
npm run build:vercel
vercel deploy --prebuilt --prod --skip-domain
# After checking the deployment, promote it to the configured custom domains:
vercel promote <deployment-url>
Use the same deployment for iam.teamofsilicons.com and auth.iam.teamofsilicons.com. Keep Vercel deployment URLs protected; the gateway intentionally rejects hosts other than these two configured domains. A static-only Vite deployment will not work. The packaging step copies only the built assets and gateway, not .env files. No GitHub repository is created or pushed by these commands. Vercel's build/runtime documentation: Node.js runtime, Build Output API.
Organization invitations can link to /join?org_id=your-org on either hostname. Sign-in preserves this allowlisted internal destination and prefills the organization handle; no arbitrary return URL is accepted.
WorkOS callback prerequisite
IAM derives its SSO callback from IAM_PUBLIC_BASE_URL. For browser SSO through this gateway, configure the backend with:
IAM_PUBLIC_BASE_URL=https://auth.iam.teamofsilicons.com/
IAM_AUTH_BASE_URL=https://auth.iam.teamofsilicons.com/
Allowlist https://auth.iam.teamofsilicons.com/api/v1/sso/callback in WorkOS. The gateway's API_UPSTREAM stays on the backend hostname. Without this configuration the backend host will not receive the encrypted frontend cookie, and SSO cannot complete. No production setting has been changed by this implementation.
Authentication and application integration
Signup verifies both email and phone, then creates a Carbon. It does not silently sign the user in: a fresh IAM login challenge establishes the session. The IAM-owned auth frontend may ask for OTPs; applications, the CLI, and the client must continue to use SLT login, not collect those OTPs themselves.
Successful browser login never returns bearer/refresh tokens to browser JavaScript. The gateway encrypts the upstream Carbon tokens and upstream browser-session cookie into an HttpOnly, SameSite=Lax cookie (Secure over HTTPS). Token refresh runs server-side, with deterministic refresh idempotency and in-process single-flight. Terminal refresh rejection expires the frontend session; transient failures preserve it.
Application login navigates through /auth/continue to IAM's /login surface. GET never grants consent or mints a token. After application confirmation, IAM displays every requested IAM and external application permission, explicitly marks critical permissions, and asks the user to continue before choosing at least one organization. The backend supplies the current scope version and determines whether that permission step is required; existing grants stay selected and additions preserve them. The trusted IAM frontend submits org_ids, the exact displayed approved_scopes, and scope_version to the direct-IAM SLT endpoint, shows loading and a success checkmark, then displays the SLT or redirects with slt. “Select all” includes current organizations only. Applications must protect their own callback flow/state and immediately exchange the SLT on their server, using application Basic credentials or the Rust client. The frontend never performs that exchange with app secrets.
The console supports app creation, detail/profile editing, webhook destinations/approval, client and webhook secret rotation, login history, failed-delivery replay, and OBO endpoint registration. App IDs are displayed canonically as org>app; creation asks for organization and local handle separately. Local app handles accept 1–80 lowercase ASCII letters, digits, underscores or hyphens, starting with a letter; the organization prefix is not counted. Webhook secrets are user supplied. Base URLs reject any path or trailing slash; webhook URLs may contain them.
OBO proof exchange and verification remain signed server-to-server operations. The console manages exposed endpoints and explains the integration. It is not an OBO request simulator, and does not trust a cached role as delegated authority. Follow the API/client integration docs for signed requests, snapshots, epochs, and current authorization.
Organization and account coverage
- Organizations: create, view, edit, ownership transfer; email invitation join and WorkOS join navigation.
- Directory: member details, directory fields, job roles/tags/history, admin/capability changes, removal; Silicon profile/create/remove, webhook setup/subscriptions and staged token rotation.
- Invitations and tags: list/create/view and revoke or edit/delete where supported.
- Trust: organization default, rule creation/edit/deletion and effective-trust evaluation. Trust is advisory.
- Approvals: pending/actionable lists, detail, approve/reject with the appropriate step-up.
- Testing: control-plane create/list/edit, key reveal/rotation, clean, recoverable deletion/restoration. Browser identity does not switch into a test environment. Use the CLI/client with its key for test-plane login/import/OBO.
- Account: profile edit, session list, current-session logout, other-session revocation and logout-all. Backend age/step-up policies remain authoritative.
The UI intentionally does not expose platform-admin review, Silicon-only governance request creation, application Basic-auth token endpoints, or provider webhooks as human browser operations. Some advanced collections use a schema-driven form with JSON inputs for object arrays; field constraints and help come from the checked-in OpenAPI schema snapshot. UUID fields are explicit, not guessed from public IDs.
Correctness and security
- Required fields, safe URL validation, opaque cursor pagination, explicit loaded-page search scope.
- Mutations own idempotency keys; ambiguous/network/in-progress retries preserve them while the form remains open. If you close or reload an uncertain submission, check the resource's current state before submitting again. Secret recovery expiry requires reconciliation, not an automatic duplicate operation.
- Versioned mutations send
If-Match. A stale version returns an actionable conflict; no silent overwrites. - Sensitive actions require confirmation and fresh, action/resource-bound step-up. Tokens and newly revealed secrets are memory-only and disappear when their dialog closes.
- CSRF defense requires exact same-origin requests and a custom frontend header for JSON API access. Only narrowly defined navigation/callback GETs are exempt. Browser-supplied bearer headers and app credentials are not forwarded.
- Fixed upstream, allowlisted frontend hosts, blocked server-to-server routes, bounded request bodies, no-store responses, safe redirect handling, and a production CSP.
- No analytics, external fonts, credential logging, browser localStorage or sessionStorage.
- A feature-detected WebMCP surface reads the current section, navigates, or stages (never submits) app creation. It exposes no credentials.
Keeping contracts current
After backend changes, regenerate schemas and review affected screens:
ruby scripts/sync-contract.rb ../docs/openapi.yaml
npm run check
npm run build
The snapshot is a form aid, not authorization enforcement. The IAM backend remains authoritative. Review the source when OpenAPI and implementation disagree, especially step-up bindings and per-resource versions. Runtime secrets, .vercel/, dependencies and build output are excluded from Git.
Repository QA evidence is retained separately from the public manual. npm test covers URL bounds, single/batch/bundle continuation, callback encoding, permission payload integrity, and gateway CSRF rejection.
Built with SolidJS, TypeScript and Vite. The mark and IBM Plex font files are reused from the existing Silicon IAM backend assets; retain their upstream licensing when distributing.
Application permissions, reviews, and bundles
Creation distinguishes app_scope (data and delegated access) from
webhook_scope (event subscriptions). Identity and profile permissions start
selected. The permission catalog includes published endpoints from other
applications, including applications in other organizations. All IAM permissions
are listed as checkboxes. To select external permissions, enter the provider's
full app_id (org>app) and load its published scopes, then check the endpoints
your application needs. An invalid or unavailable ID displays app_id invalid;
an available application with no published endpoints shows an empty-state
message. Critical permissions say “This would require approval from IAM” or
name the receiving application's ID. Webhook subscriptions also use checkboxes.
The Permissions tab shows the currently usable scope set alongside the requested set. Save non-critical additions or removals directly. For critical additions, write a review message explaining the application and every requested permission, then submit the review. An initial app remains unusable until approval; an upgrade continues using its previously approved permissions during review.
Scope reviews provides one inbox for requests your applications submit and requests your applications can decide. Every thread preserves the reviewer’s initial instructions, replies, timestamps, and final decision. A denial requires a reason. Messages render as plain text. Replies and decisions notify the other participants by email through IAM.
App bundles groups same-organization applications behind one login identity.
Create or manage a bundle in the console and use
/login?bundle_id=org%3Ebundle. The backend determines whether a bundle can be
created. Users see the bundle’s identity and choose organizations once; the
callback receives individual application SLTs in the same #slts= encoding as
batch login. Every member must exchange its own token using its own secret.
The frontend links to the standalone documentation site at
https://docs.iam.teamofsilicons.com. Its static build and hosting configuration
are in docs-site/; it is deployed separately from the authenticated frontend.