Identity environments
Your app runs in more than one place: on a laptop, in CI, on a staging server and in production. An identity environment gives each of those places its own directory of app users. A person who signs in to your local build is a different user from the same person in production, and a key made for development cannot sign anyone in to production.
Each environment has its own:
Users, with their sessions and linked social accounts. An email address is unique within an environment, so the same address can exist in two environments as two separate users.
Keys. A key with
identity:authbelongs to one environment.Web origins and redirect URIs, where a browser may call Mocco from and where social sign-in may return to.
Social provider apps, the client IDs and secrets for Google, Apple and the others.
Sign-in access, the rule for who may sign in.
Token audience, the
audclaim of the access tokens it issues.
The issuer, the signing key and the JWKS are shared by every environment of a project, and so are the provider callback URLs.
The two defaults
A project gets two environments the first time it needs one, for example when you open the App users page or create a key with identity:auth:
| Environment | Who may sign in | Audience | Web origins and redirect URIs | Use it for |
|---|---|---|---|---|
production | Anyone | The project ID | Copied from the project's apps when it was created | Your real users |
development | Workspace members | Its own ID | None | Local development and other work by your team |
production is the project's first environment. Keys, console actions and agent tools that don't name an environment use it. Its audience is the project ID, so verifiers that expected the project ID before environments existed keep working.
If your project used sign-in before environments existed, it has only production, which holds your existing users. Add a development environment yourself, as below.
Add an environment
Add one environment for each place your app runs that should have users of its own, such as staging or ci. A project can have up to ten.
In the console, open the project's App users page, then use Add environment next to the environment switcher. Give it a key (lower-case letters, digits and hyphens, up to 32 characters) and a name. The key can't be changed later. A new environment has its own audience and only workspace members can sign in to it; set its web origins and redirect URIs on its Environment settings tab.
An agent can do the same over MCP:
mocco_identity_environments_searchlists a project's environments with their IDs, audiences and settings, and the provider callback URLs.mocco_identity_environments_createadds one, with akey, aname, and optionallywebOriginsandredirectUris.mocco_identity_environments_updatechanges the name, origins, redirect URIs, sign-in access, allowed emails and test addresses.mocco_identity_environments_removeremoves one.
Changes need the identity:write scope, the workspace's agent opt-in and a confirmed round trip. Any workspace member can read environments; owners and administrators can change them.
The Overview tab shows every environment's settings side by side and marks the ones that differ, so you can check that staging matches production where it should.
Removing an environment deletes its users, their sessions and linked accounts, and its provider apps. It can't be undone. Revoke the keys bound to it first; the project's only environment can't be removed.
Get a key for an environment
A key's environment is chosen when the key is created and doesn't change. To move an app to another environment, create a new key.
Console: on the API keys page, tick
identity:auth. An Identity environment select appears; choose the environment the key signs people in to.MCP: call
mocco_api_keys_createwithidentityEnvironmentIdset to an ID frommocco_identity_environments_search. Without it, the key belongs to the project's first environment.
Use a publishable key (mk_pub_…) in a web or React Native app. See API keys for the kinds of key and where each one goes.
Web origins and redirect URIs
A publishable key works from a browser only on its project's web origins or its environment's web origins. Social sign-in may return only to an exact redirect URI of the environment, or to a URL on one of its web origins. See where sign-in may return for the rules.
Put each address on the environment that uses it:
production:https://app.example.com,myapp://auth/callbackstaging:https://staging.example.comdevelopment:http://localhost:5173,myapp-dev://auth/callback
Add localhost and other loopback addresses only to development (or another environment that real users never reach). production was seeded from your project's apps, so check that it doesn't carry a local address from before.
Social providers
Each environment has its own provider apps. Set them on the Sign-in methods tab with the environment you want selected in the switcher, or with mocco_identity_providers_set and an environmentId.
We recommend a separate OAuth app at each provider for each environment, such as "Example (development)" and "Example (production)". A development app can then stay in the provider's testing mode, and a leaked development secret doesn't touch production.
Every environment uses the same callback URL, so register the same address with each provider app:
<IDENTITY_ISSUER>/api/ext/v1/identity/oauth/<provider>/callbackThe Environment settings tab lists the callback URL for each provider. Mocco knows which environment a callback belongs to from the sign-in it started, so the shared URL never mixes environments.
If you import users who signed in with social accounts, configure the environment they go into with the provider apps your current system uses. A provider gives a person a different ID in each app. See move existing users in.
Sign-in access
Each environment says who may sign in. Choose it under Who can sign in on the Environment settings tab, or with signInAccess in mocco_identity_environments_update.
| Setting | Value | Who may sign in |
|---|---|---|
| Anyone | open | Anyone with an email address or a social account |
| Workspace members | members | An address equal to the Mocco account email of an accepted member of the workspace |
| Listed addresses | allowlist | An address under Allowed emails, or any address at a listed @domain (not its subdomains) |
Addresses are compared without case. With social sign-in, the rule is checked against the email the provider has verified; under members or allowlist, a provider account without a verified email is refused.
The rule is checked at sign-in. Someone who is already signed in keeps refreshing their session after you tighten the rule; revoke their sessions on the Users tab to sign them out now.
A staging environment that your QA team or a client should reach usually works best as allowlist with @example.com.
Test addresses for end-to-end tests
End-to-end tests can't read an inbox. With Test addresses turned on, an address whose local part ends in +mocco_test signs in with the fixed code 424242 and gets no email. It skips the sign-in access rule, so it works even where only workspace members may sign in.
Test addresses only work in an environment where sign-in isn't open. Because the code is public, Mocco refuses to turn test addresses on while sign-in is Anyone, and refuses to open sign-in while they are on. Never use test addresses in production.
Turn them on in the environment's Environment settings tab, or with testAddresses: true in mocco_identity_environments_update. Then sign in from a test the same way a person would:
import { createIdentityClient } from '@mocco/js/identity';
// `storage` keeps the session, as in the social sign-in guide; an in-memory Map is enough in a test.
const identity = createIdentityClient({ publishableKey: process.env.MOCCO_KEY!, storage });
const { challengeId } = await identity.emailStart('someone+mocco_test@example.com');
const session = await identity.emailVerify(challengeId, '424242');Or with plain HTTP:
curl -s https://api.mocco.club/v1/identity/email/start \
-H "X-Mocco-Key: $MOCCO_KEY" -H 'Content-Type: application/json' \
-d '{"email":"someone+mocco_test@example.com"}'
# → {"challengeId":"…"}
curl -s https://api.mocco.club/v1/identity/email/verify \
-H "X-Mocco-Key: $MOCCO_KEY" -H 'Content-Type: application/json' \
-d '{"challengeId":"…","code":"424242"}'In a browser test, type the test address and 424242 into your app's own sign-in form.
The usual limits still apply: the code expires after ten minutes, a wrong code counts toward the five attempts, and starting a sign-in is rate-limited. Use a different test address per test run (for example run-1042+mocco_test@example.com) when tests run in parallel. Test addresses apply to email codes only; social sign-in always follows the access rule. Once the setting is off, 424242 signs no one in.
Token audience
Access tokens carry the environment's audience as aud, and a token from one environment fails verification in another. Verify each token with the audience of the environment your key belongs to:
Read it from
/config.GET /v1/identity/configwith the environment's key returns itsaudienceandenvironmentKey. A backend can compare them with the values it expects before it enables sign-in.Pass it to the SDK.
createIdentityVerifier({ projectId, audience })in Node, orVerifierConfig { audience: Some(…), … }in Rust. See verify identity tokens.
production keeps the project ID as its audience, which is also the verifiers' default, so a production backend needs no change. Every other environment's audience is its own ID. Keep it in the same configuration as the key, for example MOCCO_IDENTITY_AUDIENCE next to MOCCO_KEY.
Local development setup
Open App users, switch to
development, and on Environment settings add your dev server's origin under Web origins, for examplehttp://localhost:5173. Add a redirect URI such asmyapp-dev://auth/callbackif a native build uses social sign-in.On API keys, create a publishable key with
identity:authand choosedevelopmentunder Identity environment.Put the key and the audience in a git-ignored
.envfile. Read the audience from/configor from the environment's settings.# .env (listed in .gitignore) MOCCO_KEY=mk_pub_… MOCCO_IDENTITY_AUDIENCE=…Start your app and sign in as yourself, with the email address of your Mocco account:
developmentadmits workspace members. Teammates who aren't members can be added under Listed addresses instead.To sign in without an inbox, turn on Test addresses and use
you+mocco_test@example.comwith the code424242.
Production deploys use a different key from the production environment, set in your hosting provider's secrets. The code stays the same; only the key and the audience differ.
Troubleshooting
| What you see | Why | What to do |
|---|---|---|
403 insufficient_scope | The key doesn't hold identity:auth | Create a key with identity:auth and choose its environment |
403 identity_environment_required | The key isn't bound to an identity environment, so there is no directory to sign anyone in to | Create a new key with identity:auth, choose its environment, and revoke the old key |
403 sign_in_not_allowed, or error=sign_in_not_allowed on your social redirect | The environment's sign-in access rule doesn't admit the address | Use a member's account email, add the address or its domain under Allowed emails, or use a test address where they are on. Under members or allowlist, a social account needs a verified email |
403 origin_not_allowed | The page's origin isn't on the project's web origins or the key's environment's | Add the origin to the environment that the key belongs to. A key of another environment is refused from that environment's origins |
400 invalid_redirect_uri | The social redirect isn't on the environment's redirect URIs or web origins | Add it to the key's environment |
The verifier rejects every token (Node authenticate returns null, Rust returns InvalidToken) | The verifier expects another environment's audience, often the project ID while the key belongs to development | Pass the audience from /config for that key |
424242 is refused | Test addresses are off, the address doesn't end in +mocco_test, or the challenge expired or ran out of attempts | Check the environment's Test addresses setting and start a new sign-in |
| Turning on test addresses is refused | Sign-in is Anyone | Choose Workspace members or Listed addresses first |