Identity
We now support integration with 3rd-party authentication providers, and will be deprecating the authenticate
action that ships with the Identity
model.
Almost every application requires authentication and for this purpose Keel comes with a built-in Identity
model. This model represents the different identities that have authenticated with your app and includes a few actions that can be used to build authentication into your product.
The Identity
model is intended to be a building block for further authentication logic and is not intended to be a complete authentication solution.
Usage in models
Since Identity
is a regular model, you can use it as a relationship field. A common use-case for this is to add Identity
to the model that represents users in your application. For instance, you might add Identity
to a Customer
model.
model Customer {
fields {
identity Identity @unique
}
}
When using Identity
like this you will probably want to mark the field as unique, so that an identity relates to a single customer.
Working with application users
To use the Identity
model for authentication, you can associate it with a User
model. A User
model represents a user in the context of your application, and may have additional fields such as name
, email
, avatar
, etc.
model User {
fields {
name String
email String
avatar String
identity Identity @unique
}
}
Then in your application, after a user has authenticated, you can create an Identity
for them and associate it with their User
record.
Usage in expressions
When writing an expression in your schema or writing a function, ctx.identity
refers to the currently authenticated Identity
. If the caller of an action is not authenticated then ctx.identity
will be null.
Filtering records by Identity
It is common to want to make APIs that only return data owned by the caller. This can be done in a Keel app by filtering the returned records by the authenticated Identity
. As an example in the following schema there is a myPosts
action that only returns the posts created by a profile that is linked to the calling Identity.
model Profile {
fields {
identity Identity @unique
posts Post[]
}
}
model Post {
fields {
profile Profile
}
actions {
list myPosts() {
@where(post.profile.identity == ctx.identity)
}
}
}
Note that filtering records like this is different from defining permissions.
Setting a field to the caller's Identity
When Identity
is used in a model as a relationship field, you should always use ctx.identity
to set it, rather than trying to accept it as an input (which won't work).
model Profile {
fields {
identity Identity @unique
}
actions {
create createProfile() {
@set(profile.identity = ctx.identity)
}
}
}
Permissions
You can use ctx.identity
in a permission expression to restrict who is allowed to perform certain actions.
model Profile {
fields {
identity Identity @unique
}
}
model Post {
fields {
profile Profile
}
actions {
get getPost(id)
delete deletePost(id)
}
@permission(
expression: true,
actions: [get]
)
@permission(
expression: post.profile.identity == ctx.identity,
actions: [delete]
)
}
@unique relationships with identity
When creating a @unique
relationship between some model and Identity
, as with many of the examples above, you will then be able to traverse from Identity
to that model in expressions. See how useful this can be in the example below.
model Customer {
fields {
name Text
identity Identity @unique
}
}
model Order {
fields {
items OrderItems[]
orderedBy Customer
}
actions {
create createOrder(items.product.id) {
@set(order.orderedBy = ctx.identity.customer)
}
update cancelOrder(id) {
@where(order.status != Status.Shipped)
@set(order.status = Status.Cancelled)
@permission(expression: ctx.identity.customer == order.orderedBy)
}
}
}