|
| 1 | +--- |
| 2 | +description: Integrating with a custom authentication system. |
| 3 | +sidebar_position: 100 |
| 4 | +sidebar_label: Custom Authentication |
| 5 | +--- |
| 6 | + |
| 7 | +# Integrating With a Custom Authentication System |
| 8 | + |
| 9 | +You may be using an authentication provider that's not mentioned in the guides. Or you may have a custom-implemented one. Integrating ZenStack with any authentication system is pretty straightforward. This guide will provide the general steps to follow. |
| 10 | + |
| 11 | +## Determining what's needed for access control |
| 12 | + |
| 13 | +The bridge that connects authentication and authorization is the `auth()` function that represents the authenticated current user. Based on your requirements, you should determine what fields are needed from it. The `auth()` object must at least contain an id field that uniquely identifies the current user. If you do RBAC, you'll very likely need an `auth().role` field available. Or even an `auth().permissions` field for fine-grained control. |
| 14 | + |
| 15 | +The `auth()` call needs to be resolved to a "type" in ZModel. If you store user data in your database, you may already have a "User" model that carries all the fields you need to access. |
| 16 | + |
| 17 | +```zmodel |
| 18 | +model User { |
| 19 | + id String @id |
| 20 | + role String |
| 21 | + permissions String[] |
| 22 | + ... |
| 23 | +} |
| 24 | +``` |
| 25 | + |
| 26 | +ZenStack picks up the model named "User" automatically to resolve `auth()` unless another model or type is specifically appointed (by using the `@@auth` attribute). For example, if you're not storing user data locally, you can define a "type" to resolve `auth()`. This way, you can provide typing without being backed by a database table. |
| 27 | + |
| 28 | +```zmodel |
| 29 | +type Auth { |
| 30 | + id String @id |
| 31 | + role String |
| 32 | + permissions String[] |
| 33 | + @@auth |
| 34 | +} |
| 35 | +``` |
| 36 | + |
| 37 | +Just remember that any thing that you access from `auth().` must be resolved. |
| 38 | + |
| 39 | +## Fetching the current user along with the additional information |
| 40 | + |
| 41 | +At runtime in your backend code, you need to provide a value for the `auth()` call to ZenStack, so it can use it to evaluate access policies. How this is done is solely dependent on your authentication mechanism. Here are some examples: |
| 42 | + |
| 43 | +1. If you use JWT tokens, you can issue tokens with user id and other fields embedded, then validate and extract them from the request. |
| 44 | +2. If you use a dedicated authentication service, you can call it to get the current user's information. |
| 45 | + |
| 46 | +You must ensure that whatever approach you use, the user information you get can be trusted and free of tampering. |
| 47 | + |
| 48 | +## Creating an enhanced PrismaClient |
| 49 | + |
| 50 | +Finally, you can call the `enhance` API to create an enhanced PrismaClient with the user information and enjoy automatically enforced access policies. |
| 51 | + |
| 52 | +```ts |
| 53 | +const user = await getCurrentUser(); // your implementation |
| 54 | +const db = enhance(prisma, { user }); |
| 55 | +``` |
0 commit comments