Create a sign-in function
This tutorial shows how you can use Fauna’s credentials feature to build a user registration and login system.
The examples in this tutorial use the Fauna Dashboard and Fauna’s demo data.
Setup
Typically, applications use an email and password to sign up new users. Each user is identified by a unique email address.
Update the Demo database to support this setup for customers.
-
In the Dashboard, open the Demo database.
-
In the Dashboard, add the following to the
Customer
collection’s schema:collection Customer { unique [.email] index byEmail { terms [.email] } ... }
The change adds a unique constraint to the email
field. Each customer must
have a unique email address.
The change also adds a byEmail
index. You can use the index to
fetch customers based on their email
.
Create a sign-up function
In the Dashboard, add the following userSignup()
function:
@role(server) // Runs with the built-in `server` role's privileges.
function userSignup(email, password) {
// Creates a `Customer` collection document.
let customer = Customer.create({
email: email
})
// Creates a credential that associates the
// `Customer` document with an end user's password.
// The `Customer` document acts an identity document that
// represents the end user.
Credential.create({
document: customer,
password: password
})
}
The function registers new customers. It accepts a customer email
and
password
. It uses the email
to create an identity document in the
user-defined Customer
collection.
It then uses the password to create a credential for the document.
Create a sign-in function
Add the following userLogin()
function:
@role(server) // Runs with the built-in `server` role's privileges.
function userLogin(email, password) {
// Uses the `Customer` collection's `byEmail` index to
// get `Customer` collection documents by `email` field value.
// In the `Customer` collection, `email` field values are unique so
// return the `first()` (and only) document.
let customer = Customer.byEmail(email)!.first()
// Gets the credential for the above `Customer` document and
// passes it to `login()` to create a token.
// The `Customer` document is the token's identity document.
// Set the token's `ttl` to 60 minutes from the current time at query.
// The token's authentication secret expires at its `ttl`.
Credential.byDocument(customer)
?.login(password, Time.now().add(3600, "second"))
}
The function lets registered users sign in. It accepts a customer email
and
password
. It uses the email
and the byEmail
index to find the customer.
It then uses the Credential.byDocument()
and
login()
methods to create a
temporary access token that’s tied to the customer.
The client application can use this token to access Fauna data on the customer’s behalf. The token automatically expires after 60 minutes (3600 seconds).
The access token has the roles assigned to the Customer
collection. For the
Demo database, the Customer
collection’s privileges are defined in
the customer
role:
role customer {
membership Customer
privileges Store {
read
}
privileges Product {
read
}
privileges Order {
read {
predicate (ref => Query.identity() == ref.customer)
}
}
...
}
The userLogin()
function runs using the built-in server
role.
Create a role for unauthenticated users
Add the following unauthUser
role:
role unauthUser {
privileges userSignup {
call
}
privileges userLogin {
call
}
}
To limit access, the unauthUser
role only has call
privileges for the
userSignup()
and userLogin()
functions. A client application can use this as
the default Fauna API key until a user logs in to generate a temporary access
token.
Test the functions
Next, run FQL queries that use the UDFs and mimic the login workflow of a client application.
-
In the Fauna Shell for the Demo database, create an API key for the
unauthUser
role:Key.create({ role: "unauthUser" })
Copy the key in the response’s
secret
property:{ id: "394634072325881920", coll: Key, ts: Time("2099-04-08T21:20:29.185Z"), role: "unauthUser", secret: "..." }
-
In the Shell, select Secret and paste in the key.
This lets you run queries using the
unauthUser
role’s privileges. -
Run the following query to mimic the registration of a new user:
userSignup("jane.doe@example.com", "password123")
The query returns a credential, but the current API key doesn’t have permission to view it. This is expected.
Credential("394635664113532992") /* permission denied */
-
Run the following query to mimic the login of the user:
userLogin("jane.doe@example.com", "password123")
The response’s
secret
property contains an access token for the user.{ id: "394634552573689922", coll: Token, ts: Time("2099-04-08T21:28:07.205Z"), ttl: Time("2099-04-08T22:28:07.046023Z"), document: Customer("394634467388424258"), secret: "..." }
-
Copy and paste the key into the Shell’s Secret.
-
Run the following query to access
Product
documents on the user’s behalf:Product.byName("limes")
The query returns a set of matching
Product
documents:{ data: [ { id: "394634876725231680", coll: Product, ts: Time("2099-04-08T21:33:16.430Z"), name: "limes", description: "Conventional, 1 ct", ... }, ... ] }
-
Run the following query to check access to the
Manager
collection:Manager.all()
The query returns an empty set:
{ data: [] }
The user’s token doesn’t grant
read
access to theManager
collection.
Is this article helpful?
Tell Fauna how the article can be improved:
Visit Fauna's forums
or email docs@fauna.com
Thank you for your feedback!