Skip to content

Commit 0e750c9

Browse files
authored
doc: guide for custom auth (#395)
1 parent 450eb4c commit 0e750c9

1 file changed

Lines changed: 55 additions & 0 deletions

File tree

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
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

Comments
 (0)