Users

User management is central to any application and central to Kinvey's backend-as-a-service.

The user management API has methods for handling typical user actions such as signup, login and logout. Using the API is as simple as calling each of those methods from the respective form and button in your app. An active user provides context for each interaction with your backend, ensuring that security is enforced and unauthorized access is disallowed. By default, a user's data is readable but not writable by other users.

A user object and its properties such as first name, last name and email are represented in the backend as an entity, and as such, most of the entity methods such as fetch and save apply.

Active User

The library has a concept of an active user which represents the person using your app. There can only be one active user at a time. All backend API calls are made with the credentials of the active user, enforcing the corresponding access control.

The active user can be obtained by initializing an instance of the Kinvey client, and then calling kinveyClient.ActiveUser.

After authenticating a user, the library automatically caches the name and current authorization token of the user in a persistent credential store. The credential store is private to the application that created it, and it is removed when the application is uninstalled.

Explicit vs. Implicit

There are two ways to set the active user in the library:

  • An explicitly set active user is one that your application will log in using a regular username and password on a login form, or via a social login through Facebook, Google, Twitter, LinkedIn.
  • An implicitly set active user is created by the library. This action happens upon the first login that the app makes from a device. The username and password of the implicit user are randomly generated.

Apps that have no explicit notion of user registration and identity, like mobile single-player games, can simply utilize the implicit login without any credentials.

For all other practical purposes the implicit user is the same as any other user; the complete user entity is cached locally, it can have custom attributes and it can be a destination for push notifications. Since an implicit login contains no credentials, it is lost upon uninstalling the application or calling logout.

The following diagram shows how the flow differs for each way to set the active user:

Active User State

User class

The User class is used to represent a user. User is a special case of normal entities, and as a result has metadata fields just like any other entity in your model.

The following user fields have specific semantics in the backend:

You can add custom attributes to the user object in the same manner that you would save properties on any entity in a collection. This is done with the User.Attributes.Add(String key) and User.Attributes[key] methods.

Saving the User

Once the user object is modified, for those changes to make it to the server, it needs to be saved.

kinveyClient.ActiveUser.Attributes.Add("fav_food", "bacon");

User updatedUser = await kinveyClient.ActiveUser.UpdateAsync();

Authentication

When a user first installs and runs your app, a login context must be established. For new users, this is done through signup. For an existing user, this can be accomplished with login.

The methods used for login and signup are implemented as static methods on the User class. An active user is set on the Kinvey client only after a login attempt is successful. Once there is an active user, operations can be performed on the User instance.

User Sessions

User sessions allow you to secure access to the app using authorization tokens that can be controlled on a per session basis. Each session, beginning with a login and ending with a logout, allows you to model well defined periods of user engagement in the app.

To set the user session expiration time on App level (applied to all environments in the app):
Kinvey Console -> App Settings -> Manage App -> User session timeout

To set the user session expiration time on Organization level (applied to all apps in the organization):
Kinvey Console -> Organization settings -> Settings -> User session timeout

App level settings (if set) override Organization level settings.

Generally, a user's session ends when it expires or when logout is called. It is possible, though, to terminate all of the user's sessions at once. Subsequent requests that use any of the destroyed tokens will be rejected.

Signup

Signup creates a new user in Kinvey. If the username does not already exist in your app backend, a new user will be created.

If the user already exists, signup will result in an error.

The username is case sensitive. When logging in, the user must use the exact same username case as stored on the backend. You can utilize Business Logic or Flex to implement case-insensitive usernames.

When using custom values for _id, you should avoid values that are exactly 12 or 24 symbols in length. Such values are automatically converted to BSON ObjectID and are not stored as strings in the database, which can interfere with querying and other operations.

To ensure that no items with 12 or 24 symbols long _id are stored in the collection, you can create a pre-save hook that either prevents saving such items, or appends an additional symbol (for example, underscore) to the _id:

if (_id.length === 12 || _id.length === 24) {
  _id += "_";
}

The newly created user is automatically logged in as the active user.

User newUser = await User.SignupAsync(username, password);

Sign up with Attributes

Optionally, when you sign up a new user, you can add a dictionary of attributes to be saved on the user at creation time.

var attributes = new Dictionary<string, JToken>
{
    { "email", "jane@smith.com" }
};
var myUser = await User.SignupAsync(username, password, attributes);

Autogenerated Users

Apps that need to access data without requiring the user to log in can request automatically generated user. Autogenerated users are given a unique random username and password in Kinvey. On successful creation, the newly autogenerated user is set as the active user in the library.

A user token is required to access any data, even if that data is shared or public. If you want to access data without requiring login or account creation up-front, we suggest the following workflow.

  1. Use signup to create an autogenerated user. Use this user to access and create data on the backend.
  2. When the app/user is ready to add personal information, update the user object's username and other properties.
  3. Save the user object.
  4. Before returning control flow to the app, reset the password.

Login

For existing users, the app needs to establish a login session before accessing data. Once a user logs in, the user context is cached on the device and subsequent uses of the app do not require another call to login.

The username is case sensitive. When logging in, the user must use the exact same username case as stored on the backend. You can utilize Business Logic or Flex to implement case-insensitive usernames.

User myUser = await User.LoginAsync(username, password);

To initiate an implicit login, simply call the LoginAsync method without passing a username or password.

User implicitUser = await User.LoginAsync();

Login is needed when a user exists in the app backend but has not been established in the application session. Common scenarios when this is necessary:

  • The application launches and an active user is not yet established
  • The application is reinstalled on the same or a new device for a user who already has an account established on the back-end
  • The user has logged out and the application needs to make more calls to Kinvey

Once the user logs in successfully, the library sets the active user and caches the user's authentication tokens for subsequent use.

To log in using a social identity provider, please go to the Social Identities section of the guide.

Login hooks

Login hooks allow you to add server-side logic right before or right after a user logs in.

Login hooks can be used for various tasks. For example:

  • Restrict login for specific users - in onPreLogin, you can return an error instead of continuing with the login process.
  • Implement failed login count - in onLoginFailure, you may store a failed login count for the user in a separate collection or the user object itself.
  • Notify on failed login - send an email or push notification to a device.
  • Notify on successful login - send an email or push notification to a device.
  • Implement a case-insensitive mechanism for username on login in one place, on the server - in onPrelogin hook, convert the username to lower case.
  • Create a login log - in onLoginFialure and onLoginSuccess add an item to a “loginLog” collection.

More details on using login hooks can be found here.

Logout

Logout clears the active user and all related data, preventing other app users from accessing it. The deleted data includes:

  • Cached tokens
  • User attributes
  • DataStore caches
  • Offline data pending to be written to the backend

Logout has no effect if there is no active user.

The following snippet shows how to logout.

kinveyClient.ActiveUser.Logout();

Logout destroys the session’s associated auth token, such that subsequent attempts to re-use that token will yield a 401 Unauthorized (error) response.

When using a third-party Single Sign-On (SSO) identity provider (such as Ping Identity), the app’s logout action will destroy active session auth tokens within the Kinvey app, but SSO tokens may persist on third-party provider sites. Logout does not terminate tokens stored at third-party SSO websites using SAML or OAuth. Cookies that maintain these sessions may enable a logged out user to reopen a session and obtain a new session auth token. For instance, using Ping Identity with SAML-Redirect, the user will remain authenticated on Ping Identity website after logging out from the associated Kinvey application. This would enable a user to login to their Kinvey app after being logged out, i.e. if they remain logged in to Ping Identity.

Keep the following considerations in mind when using logout:

  • If your app needs to persist pending offline data, remember to push or sync the user's changes before logout.

  • To persist any user attributes that were modified after the last update, save the user before logout.

  • Recreate any DataStore instances used by your app after the user logs in again. DataStore instances maintain references to cache files which get destroyed on logout. Attempts to reuse the same instance of a DataStore may result in unexpected behavior.

  • If the user was subscribed to the live service, they will be unsubscribed on logout. You will need to resubscribe the user to the live service, on a fresh login.

User Lifecycle Management

You only need to remember the user if your app is explicitly setting the active user as explained in the active user section.

Once the application process is restarted, your app re-establishes the user context automatically and retrieves details about the user. At any time, you can refresh the metadata from the server by calling the ActiveUser.RefreshAsync() method. This method requests an up-to-date copy of all user attributes from the Kinvey server.

User user = await kinveyClient.ActiveUser.RefreshAsync();

Email Verification

Building email verification into your app ensures that your users provide you with correct and valid email addresses that they own during sign-up.

Configuration

The Console exposes several options that control how email verification is handled for your app. These options can be reached by navigating to the Users section and opening its Settings panel. The following settings are available under Email Verification:

  • Require Email Verification for sign in: by default, new apps do not enforce email verification. This means that while your users can go through the email verification process, any user can log into your app—regardless of whether or not their email address is verified. In order to restrict access only to those users who have successfully verified their email addresses, enable this option. Note that when this option is enabled, you will not be able to create a new user that does not have an email address.

    • Always allow access to users created before a certain date: this option appears when you enable Require Email Verification for sign in. If enabled, any user created before the date you specify will be able to log into your app regardless of whether or not their email is verified. This option is intended to support apps with an existing user base in which users were not previously required to verify their email. The option will allow these existing users to log in, but require email verification from all new users created after the specified date.
  • Start verification automatically: if this option is enabled, a verification email is automatically sent when a user account is created, or when its email address changes. If this option is not enabled, you will need to manually initiate the email verification process for each user to verify their email address.

  • Customize Kinvey email verification: this section allow you to set up the email and web page templates that are used during the verification process.

Workflow

To request email verification, the user must have a valid email set in the email attribute. The following example shows how to send a verification email to the user.

User user = await kinveyClient.ActiveUser.EmailVerificationAsync(userID);

The user must have a valid email address set in the email attribute.

This request starts the email verification process and causes an email to be sent to the user. The email requests that they confirm their email address by clicking on a link included in the email body. The link is served by Kinvey and is valid for five days from the time of the email. The email address for a user must be stored in a property named email user object field.

Email Verification Request

The workflow completes when the user opens and clicks on the link in the email, thus confirming the ownership of the mailbox. A final email is then sent to the user letting them know that their email address was successfully confirmed.

Email Verification Completed

You can check the status of the email verification for a user.

string status = myUser.Metadata.EmailVerification.Status;

The verification workflow exposes the following states for user status:

  • sent: an email was sent in response to a verification initiate request
  • resent: multiple emails were sent in response to verification initiate requests
  • delivered: the email was successfully delivered to the user's mailbox (as reported by the remote server)
  • bounce: an email previously sent was bounced back by the remote server and couldn't be delivered
  • deferred: the mail system ran into transient problems delivering the email and deferred further attempts
  • dropped: the mail system dropped the email because of errors
  • confirmed: the user opened the email and clicked on the link enclosed in the email.

Each time the status changes, the time of change is recorded as lastStateChangeAt.

Customization of verification templates

Kinvey provides generic templates for the emails being sent and the web page being shown during the verification. If you want to, you can customize the templates' contents. You can have different text and graphics for each app and even for each app environment.

To customize the templates, take these steps:

  1. Open the Console.
  2. Navigate to Users > Collection Setting > Email Verification.
  3. Find the Customize Kinvey email verification section.
  4. Expand each template to edit it using HTML and Mustache templating.

For the email templates, a plain-text version is generated and sent along if HTML is used in the body.

Email Verification Customization

The From and Reply to fields found on the email templates can be in the form Display Name <account@example.com> or simply account@example.com.

The email is always sent from support@kinvey.com. The From and Reply to fields only set the respective email headers which may cause the message to be flagged by spam filters.

The Subject and Body fields found on the email templates and the Body of the web page support variables. Variables are automatically replaced with appropriate values just before sending each copy of the email or showing each instance of the web page. Mustache templates are used to implement variables, which take the form of tags enclosed in double curly-brackets.

The available variables are predefined and vary by template type. You can't define additional variables.

Verification Email:
  • appname—application's name
  • fname—user's first name, as specified by the first_name field in the user collection
  • username—user's username, as specified by the username field in the user collection
  • url—link that the user needs to click to verify the email and show the verification page
  • expirationTimeDays—how many days the link is valid for (from generation time)
  • expirationDate—exact date the link will expire
Welcome Email:
  • appname—application's name
  • fname—user's first name, as specified by the first_name field in the user collection.
  • username—user's username, as specified by the username field in the user collection.
  • lastChangedAt—last time the user submitted a new password
Verification successful web page:
  • appname—application's name
  • fname—user's first name, as specified by the first_name field in the user collection
  • username—user's username, as specified by the username field in the user collection
  • lastChangedAt—last time the user submitted a new password

Mustache supports basic flow control through sections. In the following example, the contents of the section starting with {{#fname}} and ending with {{/fname}} will be shown if fname is defined. The second line utilizes an inverse section to show the username in case fname is empty.

{{#fname}}<p>Dear {{fname}},</p>{{/fname}}
{{^fname}}<p>Dear {{username}},</p>{{/fname}}

For advanced usage of sections, see the Mustache documentation.

Password Reset

Users can request that our system send them an email with a temporary password reset link. This link will open a web page where they can set a new password. The user must have a valid email set in the email attribute.

// username or email address can be passed into this method
await User.ResetPasswordAsync(usernameOrEmail);

This request will send an email containing a secure time-bound link to the email address on record for the user. The link is served by Kinvey and is valid for twenty minutes from the time of the email. A link can be used for only one reset. Submitting the form will update the password for the user. The user will also receive a confirmation email when they complete the password reset.

Requesting a password reset will invalidate any active session tokens for the user and require a new login on any device using the app.

Password Reset

Until the password reset is complete, the old password remains active and valid. This allows the user to ignore the request if he remembers the old password. If too much time has passed, the email link will no longer be valid, and the user will have to initiate a new password reset.

Password Reset Email Customization

You have the option of customizing how the email is presented to your app users by specifying the from and reply-to email fields as well as the subjects and bodies of the first email and the congratulations email.

Email Verification Customization

The From Address and Reply-To Address can be in the form: Display Name <account@server.com> or just account@server.com. Be aware that even if you change these fields will still be sent from support@kinvey.com, and this might cause the message to be flagged by some mail clients.

The Subject and Email fields support mustache templates (tags within double curly-brackets). The email field supports HTML bodies, but a plain-text version will be generated and sent along in the message as well.

The available tags vary by email type. The available tags are:

Reset Email:

  • appname - the application name
  • fname - the user's first name, as specified by the first_name field in the user collection.
  • username - the user's username, as specified by the username field in the user collection. The first two lines of the default template are a switch that uses first name if available, and username if one is not.
  • reseturl - the link the user needs to click to go to the reset password page
  • expirationTimeMins - how many minutes the link is valid for (from generation time)
  • expirationDate - the exact date the link will expire

Congratulations Email:

  • appname - the application name
  • fname - the user's first name, as specified by the first_name field in the user collection.
  • username - the user's username, as specified by the username field in the user collection. The first two lines of the default template are a switch that uses first name if available, and username if one is not.
  • lastChangedAt - the time the user submitted a new password

Using a Custom Password Reset Page

Rather than using the default password reset page hosted on Kinvey, you may optionally host a password reset page on your server. A link to this page will be included in the email sent to your app's users when they reset their password. Typically, you would select this option if you want your users to see a link pointing to your domain rather than to kinvey.com, and/or brand the page in any way you like to better fit your app's visual style.

Background and Process

In order to understand where your custom page fits in, it's helpful to understand the general password reset process:

  1. A user attempts to reset their password. Your app makes a request to the password reset endpoint, either directly or via a client library.

  2. Kinvey sends an email to the user, with a link to baas.kinvey.com/rpc/:kid/:usernameOrEmail/user-password-reset-process (including parameters such as time, nonce and sig).

  3. When the user clicks the link, your app's password reset page is dynamically generated by Kinvey's servers and displayed to the user.

  4. When the user submits the form on the password reset page, their browser requests baas.kinvey.com/rpc/:kid/:usernameOrEmail/user-password-reset-complete (again, with some additional parameters), which resets their password, and displays a confirmation page.

The custom password reset page that you will host will essentially replace the third step described above. A link to your page will appear in the email sent to the user, and your page will then be responsible for parsing the required parameters from the email's link and passing them, along with the new password, onto the Kinvey endpoint mentioned in step 3.

Template

The first step in creating your custom password reset page is downloading our template:

Download Template

The template contains a very simple password reset page that is modeled after our own. It contains a few lines of JavaScript code which parse the parameters from incoming URL, as well as a form allowing the user to input his new password. When the submit button is clicked, the form will send the required parameters to the Kinvey endpoint mentioned in step 3 above.

You are free to customize this form as you wish. Be aware that the Kinvey endpoint that completes the password reset process expects the data to be presented in a certain format, and you should be careful when modifying the JavaScript code or the form elements. After you have made your changes, always make sure that the newly modified page still works as expected by trying to reset a user's password through the Kinvey Console.

When you have finished customizing your password reset page, upload it to your server and make note of the URL. You will need to enter the page's URL in the next step.

Console Configuration

Once you have customized your page and uploaded it to your server, it is time to configure Kinvey so that it uses your page instead of the default one. To do so, open the Kinvey Console, navigate to the Users section, and open the Setting panel.

Select the Password Reset tab, and enter the URL for your custom page in the input field, and press the Save Changes button. This will complete the setup process, and your new page will now be used for all future password reset requests from your app.

It is highly recommended that you now test the password reset process in order to make sure that the changes you have made to the page are compatible.

Change Password

If the user is already logged in but wants to change the password, simply set a new password property on the user object and save the user.

Forgot Username

If the user has forgotten the username to sign in, you can have Kinvey send an email with the username to the address set in the user's email field.

await User.ForgotUsername("james.bond@mi6.com");

Remove User Account

The remove operation allows you to completely delete a user account from the system as opposed to disable it.

The snippet below shows how to permanently remove a user account. Because the hard option is set to true, you will not be able to re-enable the user account after the deletion.

KinveyDeleteResponse res = await kinveyClient.ActiveUser.DeleteAsync(userID, true);

Hard removal deletes the User collection entry and frees up the username for new registrations. Any other data related to the removed user, such as entities created in other collections or local data on client devices, is not deleted.

Disable User Account

You can disable, or soft-delete, the user account rather than remove it permanently. A disabled user account remains in place; only the user's ability to access the app is blocked.

A disabled user account's name remains reserved and cannot be used by new registrations.

To disable a user account, use the remove operation, but make sure the hard option is set to false.

KinveyDeleteResponse res = await kinveyClient.ActiveUser.DeleteAsync(userID, false);

Disabling can be initiated with user credentials, provided the appropriate permissions are set. A fitting example would be an administrator removing the account on user request or the user deleting their own account from the system.

You can view and reactivate disabled user accounts through the Kinvey Console.

Lock Down User Account

The app administrator has the ability to lock down a user account using the Kinvey Console. When a user account is in a locked-down state, any incoming request authenticated with the user's credentials or that attempts to log in the user will fail.

Functionally, lock down works identically to disable, but requires Master Secret authentication. In other words, lock down cannot be performed using user credentials and should never be done from your app for security reasons.

For users under lock down, the library will attempt to wipe all user data stored locally on the device where the app is running. This happens upon login and includes both permanent storage and memory.

Use the Kinvey Console to release users from lock-down.

Global User Administration

Username Existence Check

You can check whether a specific username already exists within your app.

bool exists = await User.HasUser("james.bond");

Kinvey will respond with a boolean true if the username is already in use, or false if it is available for a new user.

User Discovery

Apps often need to share data between users or provide contact information of other users of the app. In such cases, user discovery is a way for your app to retrieve users from the user collection through a query.

When fetching other user objects, be aware that these user objects are immutable. The Kinvey backend will not allow one authenticated user to change another user's attributes. Also note that the permissions set on the User collection determine whether users can see other users in the app.

It is not possible to fetch all users with an empty query using the 'lookup' method. You should use "query.equalTo" for the query when calling the lookup method. You can lookup users based on the following criteria:

  • username
  • last_name
  • first_name
  • email
  • _socialidentity.facebook.id
var criteria = new UserDiscovery
{
    FirstName = "James",
    Email = "james.bond@mi6.com"
};

User[] lookupUsers = await kinveyClient.ActiveUser.LookupAsync(criteria);

Login with Social Identities

You can use social identities to simplify user management in your app. By offering options for your users to login using their Facebook, Google+, or LinkedIn accounts, you eliminate a source of friction by not requiring that users create usernames and passwords just for your app.

Kinvey uses its Mobile Identity Connect (MIC) framework to connect to social identity providers (IdPs). This way, you have the benefit of using unified methods for connecting to all your IdPs—social, enterprise, and so on.

Service Settings

Before you can use MIC, you need to set up a RapidAuth service in the Kinvey Console for each IdP you want to connect to.

Facebook uses the Facebook Auth connector while Google and LinkedIn use the OAuth2 connector. Consult the following tables to learn how to quickly set up these RapidAuth connectors.

Facebook

The Facebook Auth connector has the benefit of having all invariable connection and other settings set for you. For the rest of the settings, see Facebook Auth in the MIC guide.

SettingValue
Client IDFacebook-provided ID
Client SecretFacebook-provided secret
User ID Attributeid
Redirect URI'sIn case you are using a custom redirect URL (i.e., you are not using a Kinvey client SDK), whitelist it here
ScopeSpecify the user attributes to request from the IdP

Google

Start an OAuth2 RadpidAuth connector and set it up as shown below. Note that depending on your use case, you may want to configure additional settings.

SettingValue
Provider URIhttps://www.googleapis.com/oauth2/v4/token
Grant TypeAuthorization Code
Grant Endpointhttps://accounts.google.com/o/oauth2/v2/auth
Client IDGoogle-provided ID
Client SecretGoogle-provided secret
User ID Attributeid
User ID Endpointhttps://www.googleapis.com/oauth2/v1/userinfo
Redirect URI'sIn case you are using a custom redirect URL (i.e., you are not using a Kinvey client SDK), whitelist it here
ScopeSpecify the user attributes to request from the IdP

LinkedIn

Start an OAuth2 RadpidAuth connector and set it up as shown below. Note that depending on your use case, you may want to configure additional settings.

SettingValue
Provider URIhttps://www.linkedin.com/uas/oauth2/accessToken
Grant TypeAuthorization Code
Grant Endpointhttps://www.linkedin.com/uas/oauth2/authorization
Client IDLinkedIn-provided ID
Client SecretLinkedIn-provided secret
User ID Attributeid
User ID Endpointhttps://api.linkedin.com/v1/people/~?format=json
Redirect URI'sIn case you are using a custom redirect URL (i.e., you are not using a Kinvey client SDK), whitelist it here
ScopeSpecify the user attributes to request from the IdP
Include client id in token request?Yes
Include client secret in token request?Yes

IdP Settings

After setting up a service using the Kinvey Console, you need to set the IdP to work with Kinvey.

Facebook

Set your Facebook app to allow a redirect URI used internally by Kinvey. Log in to your Facebook developer account, open the app, go to Facebook Login > Settings> Valid OAuth Redirect URIs, and enter the following URI:

https://auth.kinvey.com/facebook/redirect

Customers with dedicated Kinvey instances and Progress Health Cloud customers need to prepend their Instance ID to the MIC base URL as follows:

https://<instance>-auth.kinvey.com

You can find your Instance ID on the dashboard of the Kinvey Console, next to your App Key and App Secret.

LinkedIn

Set your LinkedIn app to allow a redirect URI used internally by Kinvey. Log in to your LinkedIn developer account, open the app, find the OAuth 2.0 section and ensure that the Authorized Redirect URLs contains the following URL:

https://auth.kinvey.com/oauth2/redirect

Customers with dedicated Kinvey instances and Progress Health Cloud customers need to prepend their Instance ID to the MIC base URL as follows:

https://<instance>-auth.kinvey.com

You can find your Instance ID on the dashboard of the Kinvey Console, next to your App Key and App Secret.

Google

Set your Google app to allow a redirect URI used internally by Kinvey. Log in to Google API Console and then:

  1. Open the Credentials page.
  2. Click Create credentials > OAuth client ID.
  3. For Application type, select Web application.
  4. In the Authorized redirect URIs text box that appears, enter the following URL:
https://auth.kinvey.com/oauth2/redirect

Customers with dedicated Kinvey instances and Progress Health Cloud customers need to prepend their Instance ID to the MIC base URL as follows:

https://<instance>-auth.kinvey.com

You can find your Instance ID on the dashboard of the Kinvey Console, next to your App Key and App Secret.

Logging In

Social login relies on MIC. If an existing Kinvey user is logged in to the app, MIC updates the user account with the passed social identity information. If not, it looks for an existing Kinvey user that shares the same OAuth access token and logs them in. Finally, if such a user does not exist, MIC creates a new user account and associates the social identity with it.

Go to the Mobile Identity Connect guide to learn how to log in with MIC.

Authorization

Controlling user access to your app's resources is achieved through collection- and entity-level permissions, which rely on roles. To learn more about setting permissions, head to the Security guide. Role management is described in Roles.