Skip to content

Consent and connected applications

Before an application receives access to an account, the account owner approves the request on a consent screen. Each approval is recorded as a grant, which the owner can review and revoke later.

Consent and grants serve two different purposes. Consent prevents an application that merely knows the server’s address from obtaining tokens silently: a person always decides. The list of grants, shown to users as Connected Applications, is how a user signs an application out of every device it runs on.

The consent screen appears at the start of the authorization, before the sign-in form. It is shown for every client except installed web applications such as the WebUI:

  • Dynamically registered clients
  • Clients identified by a metadata document
  • Clients registered by an administrator
  • OAuthClients marked as first party

The screen appears in the authorization code flow and in the device flow alike. Installed applications skip it, and show their name and logo in the “Sign in to …” header of the sign-in form instead.

Consent is not remembered. The screen therefore appears at every authorization, including when an application signs the user in again.

The screen names the application, lists the requested access in plain language, and shows the host to which the browser will be redirected. Each scope is described as follows:

ScopeShown as
openidSee your account name and email address
offline_accessStay connected when you are not using it
urn:ietf:params:oauth:scope:mailRead, send and manage your email
urn:ietf:params:oauth:scope:contactsRead and manage your contacts
urn:ietf:params:oauth:scope:calendarsRead and manage your calendars
urn:ietf:params:oauth:scope:filesRead and manage your files

A first-party OAuthClient receives the account’s full permissions, so the screen shows Full access to your account in place of the scope list.

The user then decides. Allow continues to the sign-in form. Deny redirects the browser to the application with the error access_denied.

The consent screen tells the user whether anyone on the server has vouched for the application’s identity. An application registered by an administrator is verified, and it is shown with the name and logo of its OAuthClient object. Every other application is marked “Unverified application”, for one of these reasons:

  • Dynamically registered clients and clients identified by a metadata document choose their own name, and nobody on the server has checked it.
  • In the Enterprise edition, a client owned by a tenant was registered by a tenant administrator, and the server administrator has not vetted it.

A client identified by a metadata document is also shown with the hostname of its client id. That hostname is the one piece of its identity that the server has verified, because the server fetched the document from it.

Unverified applications never show a remote logo. The screen draws a monogram of the name in its place. A logo is shown in only two cases: for a registered client whose logo is a data:image/ URI, and for an installed application whose bundle contains its logo.

Each authorization creates one grant, an OAuthGrant object owned by the account. The grant records:

  • The application’s name (clientName) and the kind of client (clientKind)
  • The granted service scopes
  • The IP address from which access was granted
  • The date of the grant, and the date the application last renewed its access (lastUsedAt)

Because each authorization creates its own grant, signing in with the same application on two devices creates two grants. Each device can then be signed out separately.

Users find their grants in the Account Manager under Account › Credentials › Connected Applications. Entries for dynamically registered clients and metadata document clients are labelled as unverified. Grants issued through a first-party OAuthClient are labelled “Web application of this server”.

Users can list and delete their own grants, which the default User role allows through the sysOAuthGrantGet, sysOAuthGrantQuery and sysOAuthGrantDestroy permissions. They cannot create or change grants, and they cannot see the grants of other users.

To sign an application out, delete its entry in Connected Applications. Deleting a grant revokes the access of that application: its refresh token is refused with invalid_grant and its access tokens are rejected. The application must therefore ask the user to authorize it again. Other applications, and the same application on other devices, keep their own grants and keep working.

Deleting a grant in Connected Applications is not the only way a grant ends. Grants also end in these cases:

  • The application revokes its own tokens.
  • The account’s password is changed.
  • A superseded refresh token is presented.
  • The account is deleted.

Revocation describes these cases, and the changes that leave grants in place.

An administrator who holds the same permissions can list the grants of any account and delete them through the management API. The System Administrator role grants these permissions. The following call lists the grants of the account with id c:

Terminal window
curl -X POST https://mail.example.com/jmap/ \
-H 'Authorization: Bearer <token>' \
-H 'Content-Type: application/json' \
-d '{
"using": ["urn:ietf:params:jmap:core", "urn:stalwart:jmap"],
"methodCalls": [
["x:OAuthGrant/query", {"filter": {"accountId": "c"}}, "0"],
["x:OAuthGrant/get", {"#ids": {"resultOf": "0", "name": "x:OAuthGrant/query", "path": "/ids"}}, "1"]
]
}'

A grant is deleted with x:OAuthGrant/set and its id in destroy. The following CLI commands list the grants of the same account and delete one of them:

Terminal window
stalwart-cli query OAuthGrant --where accountId=c
stalwart-cli delete OAuthGrant --ids <grant id>