Auth Rules
All rules are global. They apply to all queries and mutations, or permitted operations unless otherwise configured differently with model-level rules/field-level rules.
Grafbase supports the following strategies to control access to data:
- Anonymous — Allow access with any valid API key
- Signed-in user — Allow access to any signed-in user
- Group-based — Allow acces to users of a group
The rules below work with all the available auth providers.
You can configure anonymous access to data. This rule is enabled by default and can't be disabled.
This means anyone with a valid API key can read/write data:
schema @auth(rules: [{ allow: anonymous }]) {
query: Query
}
You can configure signed-in access to data using a valid provider:
schema
@auth(
providers: [{ type: oidc, issuer: "{{ env.ISSUER_URL }}" }]
rules: [{ allow: private }]
) {
query: Query
}
You can configure group-based access to data based on the groups
claim of a valid JWT:
schema
@auth(
providers: [{ type: oidc, issuer: "{{ env.ISSUER_URL }}" }]
rules: [{ allow: groups, groups: ["backend", "admin"] }]
) {
query: Query
}
The user only has access if the JWT claims contain one of the allowed groups
. The following decoded JWT contains a valid groups
value admin
:
{
"exp": 1659646197,
"groups": ["admin"],
"iat": 1659559797,
"iss": "https://clerk.b74v0.5y6hj.lcl.dev",
"nbf": 1659559792,
"sub": "user_12345"
}
You can optionally set groupsClaim
for group-based auth to use a custom claim path.
Consider the following JWT provided by your issuer:
{
"header": {
"typ": "JWT",
"alg": "RS256"
},
"payload": {
"https://grafbase.com/jwt/claims": {
"x-grafbase-allowed-roles": ["editor", "user", "mod"]
}
// ...
}
}
Here the groups claim x-grafbase-allowed-roles
is nested inside of https://grafbase.com/jwt/claims
. This is declared using .
. You can provide a groupsClaim
path along with the provider
:
schema
@auth(
providers: [
{
type: oidc
issuer: "{{ env.ISSUER_URL }}"
groupsClaim: "https://grafbase\\.com/jwt/claims.x-grafbase-allowed-roles"
}
]
) {
query: Query
}
Any .
used inside of URLs will need to be escaped for the groupsClaim
value.
You can set rules globally by using the @auth
directive on schema
:
schema
@auth(
providers: [{ type: oidc, issuer: "{{ env.ISSUER_URL }}" }]
rules: [{ allow: private }]
) {
query: Query
}
You can configure rules on a per-model basis using the @auth
directive:
type User
@model
@auth(
rules: [
{ allow: private, operations: ["read"] }
{ allow: groups, groups: ["admin"] }
]
) {
name: String!
}
You can configure rules on a per-field basis using the @auth
directive:
type User @model @auth(rules: [{ allow: private }]) {
id: ID!
title: String!
password: String @auth(rules: [{ allow: groups, groups: ["admin"] }])
}
There are a few things to consider when creating field-level rules:
- You can't
create
entities with any field you can'tcreate
- You can't
delete
entities with any field you can'tdelete
- You can't
link
/unlink
entities without being able toread
the entityid
- You can't request any fields to be returned by queries or mutations you can't
read
You can restrict access to specific operations using these operation rules:
get
— Allow to query a single entitylist
— Allow to query entity collectionsread
— Combines both get and listcreate
— Allow create mutationsupdate
— Allow update mutationsdelete
— Allow delete mutations
schema
@auth(
providers: [{ type: oidc, issuer: "{{ env.ISSUER_URL }}" }]
rules: [{ allow: private, operations: ["get"] }]
) {
query: Query
}
You can also set separate rules for operations.
The following authorization enables:
- Signed-in users to perform
read
operations - Users of the
moderator
group to performupdate
operations - Users of the
admin
group to perform all operations
schema
@auth(
providers: [{ type: oidc, issuer: "{{ env.ISSUER_URL }}" }]
rules: [
{ allow: private, operations: ["read"] }
{ allow: groups, groups: ["moderator"], operations: ["update"] }
{ allow: groups, groups: ["admin"] }
]
) {
query: Query
}
- Model rules replace global rules.
- Field rules replace model/global rules.