Palbase
Sign inGet started

CLI

Auth Settings

palbase auth administers the auth module of the stack this directory is linked to — the password policy and site URL, the identity providers people sign in with, the sessions they hold, the audit trail, the mail and messages the module sends, and one person's second factor. Every subcommand is one call to /v1/management/auth on that Environment, and it lands the moment the command returns: a deploy carries code and schema, these commands carry settings, and there is nothing to push afterwards. The group holds no logic of its own — each verb names a path, sends what it was given and prints what came back — so the shapes belong to the module that answers rather than to a second vocabulary here that would drift from the first.

Quick example

# read the document the module holds
palbase auth settings get
# ▸ todoapp/main
# { … indented JSON … }

# change one field of it — the rest is read first and sent back unchanged
palbase auth settings set --password-min 12

# who can sign in, and who is signed in
palbase auth providers list
palbase auth sessions revoke-all usr_01J9Z8...

Start with auth settings get. It prints the module's own document, and that document — not this page — is the authority on which fields exist and what they currently hold.

Where these act, and what they need

Every palbase auth verb goes to https://<ref>.palbase.studio/v1/management/auth/* on the environment this checkout resolves to — one environment of the project palbase/project.json names, or the stack on this machine while the machine-local record palbase start writes exists. Two things are required and neither of them is a deploy: a link, and a credential for that stack. The surface is identical on a stack you host yourself.

Every verb announces its destination first, on stderr, so a pipeline still parses:

▸ todoapp/main

Note: Which environment that is follows the rule every target-relative command uses: palbase env use <name> selects one on this machine, and --env <name> names one for a single command. The banner names both the project and the environment, so check it before a settings change. See Which environment a command acts on.

The whole surface

Seventeen verbs, in six groups. Every path below is relative to /v1/management/auth.

CommandArgumentsFlagsRoute
auth settings getnoneGET /settings
auth settings setnone--json, --password-min, --password-max, --confirm-email, --site-urlPUT /settings
auth providers listnoneGET /providers
auth providers enable <name>exactly onePOST /providers/<name>
auth providers disable <name>exactly onePOST /providers/<name>
auth providers config set <name>exactly one--jsonPUT /providers/<name>/config
auth providers config clear <name>exactly oneDELETE /providers/<name>/config
auth sessions listnoneGET /sessions
auth sessions revoke <session-id>exactly oneDELETE /sessions/<id>
auth sessions revoke-all <user-id>exactly onePOST /users/<id>/sessions/revoke-all
auth auditnone--limit, --cursor, --event-typeGET /audit
auth templates listnoneGET /templates
auth templates get <key>exactly oneGET /templates/<key>
auth templates set <key>exactly one--jsonPUT /templates/<key>
auth templates send-test <key>exactly one--jsonPOST /templates/<key>/send-test
auth mfa get <user-id>exactly oneGET /users/<id>/mfa
auth mfa reset <user-id>exactly oneDELETE /users/<id>/mfa

What every one of them prints

palbase auth always emits JSON, indented, because the same surface serves a panel and a shell pipeline and the shell's end of it has to be parseable rather than prose with a body somewhere inside it. Three cases:

The stack answersYou get
a JSON bodythat body, re-indented two spaces
204, or an empty bodynothing at all — not an invented ok
400 or worse<error>: <error_description>, and a non-zero exit

The refusal is the module's own, carried out rather than replaced: it knows which field was wrong and the CLI does not, so a sentence invented here would hide the only useful one. When the body is not an error envelope you get the stack answered <N>: <body> instead. Either way the exit status is non-zero — a script that read a 400 as a change is how somebody believes a setting landed when it did not.

auth settings set reads before it writes

This is the one behaviour on the page that will cost you data if you do not know it.

The module's PUT /settings replaces the whole document. A body that mentions three fields does not merge into the fourth — it erases it. So when you name individual settings with the typed flags, auth settings set performs a GET /settings first, lays your changes over what came back, and sends the complete document. Only the flags you actually changed are included, which is why --password-min 12 does not also set the password ceiling to zero on its way past.

The measurement that put the read there: --password-min 13 alone was refused by the module with password_max_length must be between password_min_length and 64, because the absent maximum arrived as 0. A person saying "make the minimum 13" is not saying "and forget everything else".

The merge order is: the current document, then --json, then the named flags. So --json can carry any field the four flags do not cover, and a named flag wins over the same field inside --json.

Warning: --json on its own does not read first. With no named flag there is nothing to merge into, so what you pass is sent as-is and replaces the whole document — including every field you left out. If you are editing by hand, start from palbase auth settings get and send back a complete document.

Four flags name four of the module's fields:

FlagField it writesHelp text
--password-minpassword_min_lengthshortest password this project accepts
--password-maxpassword_max_lengthlongest password this project accepts
--confirm-emailconfirm_email_requiredrequire a confirmed address before sign-in
--site-urlsite_urlthe address links in this project's mail point at

Typed flags exist so you do not have to know those field names: --json '{"password_min_length":10}' asks you to spell one correctly, and a name spelled wrong is a settings write that silently does nothing, because the module ignores fields it does not read.

Name nothing at all and the command refuses rather than sending an empty document:

nothing to send: name a setting (--password-min, --password-max, --confirm-email, --site-url) or pass the whole document with --json

A malformed --json is caught before anything is sent: --json is not valid JSON.

Providers

Google, Apple, Microsoft and GitHub use explicit browser and native client records. Email and phone retain their own settings. Inspect the configured records with:

palbase auth providers list

Server secrets are stored separately and never written into app config. For example, put a Google web secret in a local, uncommitted google-secret.json:

{"provider":"google","kind":"oauth_client_secret","client_secret":"YOUR_GOOGLE_WEB_SECRET"}
palbase auth providers config set google --credential google-web --json @google-secret.json
palbase auth providers config set google --json @google-clients.json

google-clients.json can configure all three platforms together:

{
  "enabled": true,
  "browser_clients": [{
    "key": "google-web", "enabled": true,
    "application_key": "consumer", "platform": "web", "variant": "release",
    "web_client_id": "WEB.apps.googleusercontent.com", "credential_ref": "google-web",
    "return_uris": ["https://app.example.com/auth/callback"]
  }],
  "native_clients": [{
    "key": "google-ios", "enabled": true,
    "application_key": "consumer", "platform": "ios", "variant": "release",
    "bundle_id": "com.example.app", "ios_client_id": "IOS.apps.googleusercontent.com",
    "redirect_uri": "com.googleusercontent.apps.IOS:/oauthredirect"
  }, {
    "key": "google-android", "enabled": true,
    "application_key": "consumer", "platform": "android", "variant": "release",
    "package_name": "com.example.app",
    "android_client_id": "ANDROID.apps.googleusercontent.com",
    "server_client_id": "WEB.apps.googleusercontent.com",
    "signing_certificate_sha1": "0123456789ABCDEF0123456789ABCDEF01234567"
  }]
}

Use the actual identifiers registered with Google. Android server_client_id must be a Web application client ID; android_client_id belongs to the package and signing certificate. Google IDs share a textual format, so spelling alone cannot prove their platform type.

Apple browser clients use a services_id and a separate apple_signing_key credential (team_id, key_id, PKCS#8 P-256 private_key). Native Apple clients use their bundle_id and do not need a client secret.

Microsoft clients specify an application_id and directory (common, organizations, consumers, or tenant plus tenant_id); native clients also specify their bundle/package and exact redirect URI.

GitHub uses browser clients. Studio's provider editor exposes these same fields.

Supplied browser_clients or native_clients arrays replace that complete list; omitted fields remain unchanged. Unknown fields, duplicate JSON keys, null values and invalid combinations fail before a write. Secrets must come from --json @file or stdin (--json -), and a secret write replaces the complete credential. Nothing guesses a platform from an old client_id.

palbase auth providers enable google
palbase auth providers disable google
palbase auth providers config clear google
palbase auth providers config clear google --credential google-web

Disabling retains the records. config clear disables and removes client records; adding --credential deletes only an unreferenced server credential. Writes use the current ETag with If-Match; concurrent changes return an error and are not retried against a newer revision automatically.

The existing palbase link command writes each platform's selected, public oauth snapshot. In palbase/project.json, bind the checkout to its configured application and variant:

"oauth": {
  "web": {"application_key":"consumer","variant":"release"},
  "ios": {"application_key":"consumer","variant":"release"},
  "android": {"application_key":"consumer","variant":"release"}
}

This is a field inside the existing project document; keep its other fields. If several enabled clients of one provider match the target, add client_keys to select exactly one per provider. Separate debug/release or flavor registrations use distinct client records and matching selections. Web selection is explicit. Native inference is allowed only when the checkout identifies one configured target; Android flavors and application ID suffixes require explicit selection, and the Gradle plugin validates the final build's application ID and runtime signing certificate.

palbase link

Client-setting mutations refresh already linked app artifacts through this same path. A backend save followed by failed local generation reports both facts; rerun palbase link after fixing the generation error. Failed link generation preserves the previous artifacts. Disabling or removing a client removes its emitted OAuth configuration on the next successful link.

Sessions

palbase auth sessions list
palbase auth sessions revoke ses_01J9Z8...
palbase auth sessions revoke-all usr_01J9Z8...

revoke ends one session; revoke-all ends every session one person holds. They are separate verbs on purpose: a lost laptop is one session, and the other verb is for a compromised account. Conflating them would make the common case cost more than it should.

These are the sessions of your project's end users, not Palbase accounts. Nothing on this page touches who can administer the Project itself — that is the Studio.

The audit log

palbase auth audit --limit 50
palbase auth audit --event-type login --limit 20
palbase auth audit --cursor <cursor-from-the-previous-page>

Three optional filters, passed straight through as query parameters: --limit (sent only when greater than zero, so the module's own default applies when you omit it), --cursor to continue from a previous page, and --event-type to keep one kind. The event types and the cursor's shape come from the answers themselves; the CLI knows neither.

Note: The query string is assembled by concatenation, with no percent-encoding. A cursor or event type containing &, =, + or a space will not survive the trip intact. Cursors returned by the module round-trip in practice; hand-written filters with those characters do not.

palbase auth audit is the only per-change record this settings family keeps, and it covers the auth module alone. A settings change made here is not reviewable in a pull request and is not undone by reverting one — see Stack Settings.

Templates

The mail and messages the auth module sends — and the one verb that proves the whole chain works.

palbase auth templates list
palbase auth templates get confirm_email
palbase auth templates set confirm_email --json '{"subject":"Confirm your address","body":"…"}'
palbase auth templates send-test confirm_email --json '{"to":"you@example.com"}'

Template keys and the body shape a set accepts come from the module: templates list names the keys this stack holds, and templates get <key> shows one in full. confirm_email above is a placeholder for whatever list prints — the CLI ships no list of keys and cannot check the one you typed.

send-test really sends, once, to a real address. The only way to know a template renders and a provider delivers is to send it, and finding that out here beats finding it out from the first person who signs up. It needs a configured sender on the stack — see palbase notifications on Stack Settings.

MFA

palbase auth mfa get usr_01J9Z8...
palbase auth mfa reset usr_01J9Z8...

get shows what that person has enrolled. reset clears it, through the module's only MFA mutation, DELETE /users/<id>/mfa — the three-in-the-morning verb, for somebody who lost the phone that holds their authenticator. It is reversible in the sense that matters: they enrol again.

There is no enrolment verb here. Enrolling a factor is something the person does in your app, through the client SDK.

What this surface does not reach

The auth module publishes more than the CLI wraps. These routes exist on the same /v1/management/auth base and have no palbase auth verb, so today they are reachable only by calling the stack's Management API directly:

GET|PUT /v1/management/auth/providers/phone/settings
POST    /v1/management/auth/users/{id}/credentials/revoke-all
POST    /v1/management/auth/users/{id}/reset-password
GET     /v1/management/auth/users/{id}/export
GET     /v1/management/auth/users/{id}/consents

That surface takes Authorization: Bearer <token with the management claim> or apikey: <service-role key>, and never DPoP. The CLI surface covers the credential rules; the two API keys has the service-role key palbase apikey reveal prints.

  • Stack Settings — storage, flags, egress and notification senders, written through the same door
  • Linking a Checkout — which stack these commands act on, and where the credential comes from
  • Secrets — the Environment vault, and palbase run
  • Authentication — reading the signed-in user from backend code
  • CLI: Overview — the whole command surface and how each command is credentialed
  • The Studio — Palbase accounts, which nothing on this page touches