blocks-iam-sso-oidc-configuration
Skill42 starsChanged 14 days agoMITView on GitHub
Enable/configure SSO for a Blocks project — register an OIDC client and identity provider so end users can log into the app via hosted login. Use for 'enable SSO', 'set up an OIDC identity provider', 'configure single sign-on', 'add a login provider'. CLI-driven by default (`blocks auth oidc-clients *` / `auth idp *`, project-scoped, --dry-run→--yes), not portal-only — the portal remains a valid alternative, especially for federated external providers (Google/Azure/Okta). Don't confuse with `blocks login` (the CLI's own login — see blocks-bootstrap).
In this repository27 other files it gives its agents.
- AGENTS.mdAGENTS.md
- bootstrap/agents.mdAGENTS.md
- CLAUDE.mdCLAUDE.md
- blocks-bootstrapSkill
- blocks-captchaSkill
- blocks-data-gateway-configurationSkill
- blocks-data-gateway-crudSkill
- blocks-data-storageSkill
- blocks-frontend-local-httpsSkill
- blocks-functionsSkill
- blocks-iam-access-controlSkill
- blocks-iam-accountSkill
- blocks-iam-mfaSkill
- blocks-iam-organizationsSkill
- blocks-iam-sso-oidc-implementationSkill
- blocks-iam-usersSkill
- blocks-localization-configurationSkill
- blocks-localization-implementationSkill
- blocks-mailSkill
- blocks-notificationSkill
- blocks-notifierSkill
- blocks-proxySkill
- blocks-release-deploymentSkill
- blocks-secretsSkill
- blocksSkill
- blocks-storage-configurationSkill
- blocks-workflowSkill
The file
We split this skill into the rules it gives an agent
7 rules. About 0 are common, 1 is distinctive, and 6 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈1
Distinctive · estimate
This author's own choices. Worth a look.
6
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 6
When invoking a project-scoped blocks command, either use the resolved account's saved selection or pass --project <tenantId> for that one …
- Distinctive: line 16
Don't conflate the CLI's own login with the identity provider this skill configures.
- Very specific: line 25
If the user is asking "how do I get blocks logged in" or hits not_logged_in, that's blocks-bootstrap, not this skill.
- Very specific: line 29
All of these commands are project-scoped: they need a selected project (blocks use <tenantId> or --project) and run against an impersonated …
- Very specific: line 71
Every create/update/delete/status/rotate-secret command above follows the same pattern as the rest of blocks:
- Very specific: line 76
Never raw fetch/curl these endpoints to route around the CLI's confirmation/dry-run discipline — use the commands above so the same …
- Very specific: line 82
Do not assume re-saving repairs an incomplete provider: If verification shows null endpoint fields, use idp update with values read from a …
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
When invoking a project-scoped blocks command, either use the resolved account's saved selection or pass --project <tenantId> for that one command without changing saved state. --project applies to CLI commands only, never SDK calls.
Blocks IAM — SSO / OIDC Configuration
Local snapshot: blocks/auth/ holds a read-only snapshot of the project's auth config, OIDC clients and identity providers, written by blocks pull --only auth. Read it for context before listing things one by one; check its _meta.tenantId and _meta.pulledAt, and pull again if it's stale or after you change anything. Never edit it to change the project: editing does nothing, so use the commands below. Secret fields in it are ***.
Setting up SSO for a Blocks project means provisioning two related tenant records: an OIDC client (the app-facing public client used for hosted login) and an identity provider (the record the hosted-login redirect/callback flow actually authenticates against). Both are exposed by real, implemented blocks CLI commands — this is not a portal-only action.
The one thing to get right: which login is this?
Don't conflate the CLI's own login with the identity provider this skill configures.
blocks login | The one THIS skill covers | |
| What it's for | Lets blocks itself authenticate | Lets end users log into the user's own app via hosted SSO |
| Client type | Packaged into the CLI - nothing to register, no secret to hold | Public (browser client, no secret) |
| Registered via | Nothing to register - just run blocks login | blocks auth oidc-clients save / blocks auth idp create, or the portal |
| Owned by | blocks-bootstrap skill | This skill, handing off to blocks-iam-sso-oidc-implementation |
If the user is asking "how do I get blocks logged in" or hits not_logged_in, that's blocks-bootstrap, not this skill. This skill is about the identity provider that sits in front of the user's own application's login page.
Decision tree
All of these commands are project-scoped: they need a selected project (blocks use <tenantId> or --project) and run against an impersonated project token, not the CLI's own account token.
- Check for an existing OIDC client.
blocks auth oidc-clients list [--json]/blocks auth oidc-clients get <clientId> [--json].client_secretis excluded from list/get responses — you only ever see it once, at creation orrotate-secrettime. If a suitable public client already exists (matching redirect URI / display name), reuse its id — you're done, skip to handoff. To add a redirect URI to an existing client (the common case after a deployment gets its URL), re-save with--item-id <clientId> --redirect-uris "<full list incl. the new one>"— the CLI reads the stored client and merges, so every unmentioned field (--auto-redirect, PKCE, scopes, …) is kept; only the list you pass is replaced. Thengetit back to confirm.redirect_uri_not_registeredat login is exactly this: registerhttps://<origin>/login/callbackfor EVERY origin the app is served from — the local HTTPS dev origin and each deployed URL (blocks release repos list --json, theurlfield).release setup/deploy/domain setcheck this themselves and can append it with--register-callback. If none exists, create one:
blocks auth oidc-clients save \ --client-display-name "<app name>" \ --client-type public \ --redirect-uris "https://<app-domain>/login/callback" \ --require-pkce --active \ --scope "openid profile" \ --register-as-identity-provider \ [--dry-run] [--yes]--require-mfa [--allowed-mfa-methods 1,2]belongs here too when this client must force MFA. It is a third, independent MFA gate: IAM's login policy requires MFA if the tenant requires it, the user's role requires it, the user enrolled voluntarily, or the client setsrequireMfa.allowedMfaMethodsnarrows, never widens — IAM intersects it with the tenant's allowed list, so naming a method the tenant hasn't enabled leaves nothing usable. Values are IAM'sUserMfaType(1TOTP,2Email;0is None and3/4have no provider) — see blocks-iam-mfa.This mirrors exactly what
blocks new web's interactive OIDC-client prompt does when scaffolding a new web app.--register-as-identity-provideris what turns this from "just an OIDC client" into something the hosted-login redirect flow (auth.idp.redirectToProvider()/auth.idp.callback()) can authenticate against — per the CLI's own scaffold help text, this registers the client "as a Blocks OIDC identity provider" in the same call.- Verify the auto-created provider before handing off.
--register-as-identity-providercreates the provider record for you. Current CLI builds the provider discovery URL by default, matching the portal checkbox behavior, but still check what landed withblocks auth idp list --json. If an older provider hasauthorizationUrlnull, hosted login will not redirect: the initiate call behindauth.idp.redirectToProvider()builds its target asprovider.AuthorizationUrl ?? ""plus a query string, so the browser navigates to the app's own origin with OIDC params attached. The repair:blocks auth idp update <providerItemId> \ --authorization-url "<tenant authorize endpoint>" \ --token-url "<tenant token endpoint>" \ --user-info-url "<tenant userinfo endpoint>" \ [--dry-run] [--yes]idp updateis the only route that persists these three — IAM's create path accepts them in its request model and drops them, and the repository's update is a plain replace with no re-discovery, so values set here stick. Read the tenant's discovery document for the correct endpoint values rather than composing them by hand — see the last footgun. - Inspect/manage the resulting identity-provider record with
blocks auth idp list [--json]/blocks auth idp get <id> [--json]. Useblocks auth idp status <id> --active|--active=falseto enable/disable without deleting, andblocks auth idp delete <id>to remove it — deleting an identity provider also deletes its related OIDC client registration, so treatidp deleteas the higher-blast-radius operation of the two. blocks auth idp create/updateexist as a separate, more general path for constructing an identity-provider record directly — most relevant when federating an external identity provider (Google, Azure AD, Okta, etc.) rather than using Blocks' own OIDC client as the login mechanism:blocks auth idp create --provider <p> --provider-type <t> --protocol <proto> \ --client-id <id> [--client-secret <secret>] [--display-name] [--issuer] \ [--scope] [--redirect-uris a,b] [--active] \ [--authorization-url] [--token-url] [--user-info-url] [--jwks-uri] \ [--well-known-url] [--response-type] [--grant-types a,b] [--require-pkce] \ [--token-endpoint-auth-method] [--initial-roles a,b] [--initial-permissions a,b] \ [--icon] [--body '<json>'|--file <path>] [--dry-run] [--yes]--provider,--provider-type,--protocol, and--client-idare required on create, and are immutable afterward —auth idp update <id>accepts the same flags but IAM requires you to either omit them or echo the existing values exactly. Apple-specific fields (teamId,keyId,privateKey,appleAudience) go through--body/--fileso no private key lands in shell history. Note thatcreatestoresissuer,jwksUriandwellKnownUrlbut silently dropsauthorizationUrl,tokenUrlanduserInfoUrl— pass those toidp updatein a second call. How exactly aclientIdpassed here pairs with an OIDC client record is not shown anywhere documented — the two collections are related (per the cascading delete behavior above) but the create/update commands don't expose an explicit "link to this OIDC client" field beyond passing the same id. If you need to federate an external provider, treatidp create's field values as IAM's contract and confirm anything beyond the flags above against the tenant's actual behavior rather than guessing.- Hand off. Once a client id (and, if relevant, an identity-provider id) exists, the frontend wiring — login button, callback route, token handling,
client.auth.idp.initiate()/redirectToProvider()/.callback()from@seliseblocks/client— is owned by blocks-iam-sso-oidc-implementation. Do not duplicate that work here; route to it.
Mutation discipline
Every create/update/delete/status/rotate-secret command above follows the same pattern as the rest of blocks:
--dry-runprints the request body and target endpoint without sending it (secrets are redacted in the printed body).- Without
--dry-run, the command prompts "Type 'yes' to continue" before mutating anything, unless--yesis passed to skip the prompt. - These are real tenant-security actions (an identity provider or public OIDC client controls who can authenticate as a given app's users) — always show the user what will happen (favor
--dry-runfirst) rather than running mutations silently, and don't add--yesto a call the user hasn't actually approved.
Never raw fetch/curl these endpoints to route around the CLI's confirmation/dry-run discipline — use the commands above so the same guardrails apply.
Verified footguns
--client-type publicis not cosmetic — omitting it stores a browser app as confidential. IAM derivestokenEndpointAuthMethodfromclientType:public(or any device-flow client) becomes"none", anything else becomes"client_secret_post". Leave--client-typeoff and a PKCE SPA is persisted as a confidential client that is also eligible for theclient_credentialsgrant. Always pass--client-type publicfor a browser client.--require-pkcealone does not imply it.- The CLI supplies one discovery field; endpoint population is backend behavior.
oidc-clients save --register-as-identity-providerand interactivenew websendexternalDiscoveryEndpoint, derived from the OIDC URL and tenant unless explicitly overridden. This repository cannot prove that production IAM successfully resolves it or fillsauthorizationUrl,tokenUrl,userInfoUrl,jwksUri, andissuer; verify the provider after creation. - Do not assume re-saving repairs an incomplete provider. If verification shows null endpoint fields, use
idp updatewith values read from a successfully fetched discovery document, or recreate only after explicit approval. - PKCE and the discovery URL exist on both records and mean different things.
requirePkceon the OIDC client governs the app's own authorize flow;--require-pkceonauth idpgoverns the upstream handshake the initiate call performs.--external-discovery-endpointon the client is read only as the linked provider'swellKnownUrl; on the provider record itself use--well-known-url. - Do not compose the tenant's own discovery or authorize URL from a template.
DiscoveryControllerdeclares/{tenant_id}/.well-known/openid-configurationas an absolute route, outside the/iam/v4prefix that every other IAM endpoint sits behind, and everywellKnownUrlexample in IAM's own source and tests is an external provider (accounts.google.com,login.microsoftonline.com,idp.example.com) — there is no in-repo example of a Blocks tenant pointing at itself. Whether that route resolves through theblocksapi.<domain>gateway as-is or needs an extra segment is not settled in source. Fetch the tenant's discovery document and read the endpoints out of it, or ask the user; do not assert a shape you have not seen respond.
Secondary, optional: the SDK's identityProviders admin methods
@seliseblocks/client (see auth-client.ts, the readonly identityProviders = { list, get, create, update, updateStatus, delete } block) also exposes typed methods that call the same identity-provider resource the CLI's auth idp commands hit. Reach for this when you're building an in-app admin settings screen for a signed-in administrator, where they click a button labeled something like "Add identity provider" and they fill in a form, in the moment they personally intend to make that change:
// A settings page for a signed-in admin user. The admin types into the form
// and clicks "Save" themselves — the SDK call fires from THEIR click handler.
async function onSaveClicked(formValues: IdentityProviderFormValues) {
await client.auth.identityProviders.create(formValues); // admin-initiated, in the moment
}Request/payload types on these SDK methods are intentionally loose (Record<string, unknown> passthrough) — confirm field names against the same contract the CLI's auth idp create flags document (provider, providerType, protocol, clientId, etc.) rather than guessing new ones.
Related skills
- blocks-bootstrap — owns
blocks loginitself (authenticates with no setup, nothing to register or look up). Go there first ifblocksitself isn't authenticated, or if the user is conflating "logging in the CLI" with "SSO for my app." - blocks-iam-sso-oidc-implementation — owns everything that happens once an identity provider/client id exists: wiring the login button, callback route, and token/session handling in the scaffolded React app using
@seliseblocks/client. This skill hands off to it and does not duplicate its content.
Example trigger prompts → routing
- "Enable SSO for my project" / "Set up an OIDC identity provider" / "Configure single sign-on for my app" → confirm it's the app's end-user login (not the CLI's), run the decision tree above (
auth oidc-clients list/get→auth oidc-clients save --register-as-identity-providerif none exists), then hand off to blocks-iam-sso-oidc-implementation. - "Register an OIDC client so users can log in" →
blocks auth oidc-clients list/getfirst to avoid duplicates, thenblocks auth oidc-clients savewith--dry-runshown to the user before confirming. - "Can you just create the identity provider via the API so I don't have to click through the portal?" → yes — walk them through
blocks auth oidc-clients save/blocks auth idp createwith--dry-runfirst, get explicit confirmation before dropping--yes, and mention the portal (https://os.seliseblocks.com) as an alternative if they'd rather use a GUI, especially for federated external providers where they need to register with that provider first. - "blocks login isn't working" / "not_logged_in" → this is the CLI's own login, not this skill — route to blocks-bootstrap.
- "I want an admin page in my app where I can manage identity providers" → this skill's SDK section applies: help build the settings screen calling
identityProviders.list/create/update/deletefrom the admin's own button clicks.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

