---
url: https://docs.tailor.tech/erp-kit/develop/security.md
description: >-
  How users sign in to an ERP Kit app, how permissions reach them, and the
  template settings to change before anyone else signs in.
---

# Security and Sign-in

This page covers how people sign in to the app you build with ERP Kit, and the settings to tighten before go-live. For access to the ERP Kit packages themselves, see [Registry access](/erp-kit/get-started/registry-access).

## How sign-in works

The app templates use the platform's [built-in IdP](/guides/auth/integration/built-in-idp), configured with `defineIdp` in `backend/tailor.config.ts`:

* **Sign-in page.** Users sign in on a page hosted by Tailor Platform, not by your app. The frontend's `default` OAuth2 client is a public client with DPoP, and its redirect URIs are the deployed `default-web` site and `http://localhost:5173`. See [Log in to your app](/guides/auth/app-login).
* **User profile.** Each sign-in identity maps to a `User` record from the `user-management` module, matched by email. The user's `permissions` attribute comes from the roles assigned to that user.
* **Creating users.** The template's `createUser` resolver creates the `User` record through the module command and the sign-in identity in the IdP in one step. Create users through it, not directly in the IdP, so the two stay in sync.
* **Machine users.** The `developer` machine user is for the CLI and scripts. It carries the module permissions directly and has no sign-in identity.

### Restrict sign-in to your domains

Set `userAuthPolicy.allowedEmailDomains` to the email domains your users have:

```typescript
const idp = defineIdp("default", {
  // ...
  userAuthPolicy: {
    allowSelfPasswordReset: true,
    allowedEmailDomains: ["example.com"],
  },
});
```

To add a "Sign in with Google" or "Sign in with Microsoft" button, see [Google OAuth](/guides/auth/integration/built-in-idp#google-oauth) and [Microsoft OAuth](/guides/auth/integration/built-in-idp#microsoft-oauth). For single sign-on with your own identity provider and user provisioning, see [Authentication](/guides/auth/overview) and [SCIM](/guides/auth/scim).

## Security defaults

The templates are set up for a first deploy by one developer. Change these before anyone else signs in, and before you deploy to staging or production. Each is a small change in `tailor.config.ts` or a seed file.

| Setting                                       | Template default                                                                                                      | Set it to                                                                                                                                                      |
| --------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `userAuthPolicy.allowedEmailDomains`          | Not set. An empty list currently allows every domain, but [that is changing](/sdk/services/idp)                       | Your company's email domains. Never `["*"]` for an internal ERP.                                                                                               |
| Seeded admin in `seed/data/_User.jsonl`       | A fixed password committed to the repository                                                                          | Change the password after the first sign-in, and delete the seeded user once a real admin exists. Do not seed it into staging or production.                   |
| IdP permissions                               | `_loggedIn` for create, read, update, delete, and password reset, so any signed-in user can create sign-in identities | The admin permission scope only                                                                                                                                |
| `defaultPermission` on the resolver namespace | `_loggedIn`                                                                                                           | Keep it, and give each resolver that needs more its own permission.                                                                                            |
| `gqlOperations`                               | `"query"`: tables are read-only over GraphQL and writes go through resolvers                                          | Keep it.                                                                                                                                                       |
| `disableIntrospection`                        | Not set (`false`)                                                                                                     | `true` in production                                                                                                                                           |
| `cors`                                        | Includes `http://localhost:5173`                                                                                      | Remove `localhost` entries in production.                                                                                                                      |
| OAuth2 clients for AI agents                  | Not in the template                                                                                                   | Register agent clients such as a [Claude connector](/guides/integration/claude) in development and staging only, unless you have reviewed them for production. |

For network-level restrictions, see [IP restriction](/administration/ip-restriction).
