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:
- Signed-in user — Allow access to any signed-in user
- Owner-based — Allow access to the owner only
- Group-based — Allow access to users of a group
The rules below work with all the available auth providers.
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 access to data so that it can only be accessed by the owner.
The owner of data is currently set using the value of the sub
claim inside the authorization token with requests at the time the data is created.
Owner based auth is evaluated based on the presence of the sub
claim:
- If the
sub
claim is present and there are owner-based rules set, the owner-based rules are applied. - If the
sub
is present but there are no owner-based rules set, the group-based rules are applied.
schema
@auth(
providers: [{ type: oidc, issuer: "{{ env.ISSUER_URL }}" }]
rules: [{ allow: owner }]
) {
query: Query
}
- Data can only have one owner.
- Owner-based rules can only be set globally.
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
}
You can combine rules at any level:
schema
@auth(
providers: [{ type: oidc, issuer: "{{ env.ISSUER_URL }}" }]
rules: [
{ allow: private, operations: [read] } # Signed-in can read only
{ allow: groups, groups: ["admin"] } # Full access
{ allow: owner, operations: [create, update] } # read, create, update
]
) {
query: Query
}
- Model rules replace global rules.
- Field rules replace model/global rules.