A Sandstorm app delegates authentication to the Sandstorm platform. This page explains how to identify human visitors to an app via HTTP(S). For information on authenticating mobile apps, native clients, and other automated agents, see Exporting HTTP APIs.
When a web app runs within Sandstorm, Sandstorm sanitizes all HTTP
requests. By default, it passes requests to your app via a tool called
sandstorm-http-bridge. This results in a few interesting properties:
Sandstorm knows which user is making the request, so it can add headers indicating the currently logged-in user's name ("authentication").
Sandstorm knows which permissions the user has -- for example, it knows if the user owns this grain -- so it can add headers indicating what permissions the user has ("authorization").
When your app receives HTTP requests,
sandstorm-http-bridgehas normalized them. If a user's browser is speaking some non-compliant dialect of HTTP, your app doesn't have to handle it.
Headers that an app receives
sandstorm-http-bridge, an app receives the following headers
related to user identity and permissions:
X-Sandstorm-Username: This is set to the user's full name, in percent-encoded UTF-8. For example, the username
"Kurt Friedrich Gödel"will appear as
"Kurt%20Friedrich%20G%C3%B6del". For anonymous users, this header will simply contain "Anonymous%20User".
X-Sandstorm-User-Id: If the user is logged in, this is set to the user's current user ID, which is the first 128 bits of a SHA-256. For example:
0ba26e59c64ec75dedbc11679f267a40. This header is not sent at all for anonymous users.
X-Sandstorm-Tab-Id: Unique identifier for the grain tab in which this request is taking place. This can be used to correlate multiple requests being performed in the same tab even when the user is anonymous. Also, for HTTP APIs, requests using the same API token will have the same tab ID, to allow you to correlate requests from the same client.
X-Sandstorm-Permissions: This contains a list of the permissions held by the current user, joined with a comma such as
edit. Permissions are defined in the package's
sandstorm-pkgdef.capnp. The grain's owner holds every permission and can use the "Share access" button to authorize other users.
X-Sandstorm-Preferred-Handle: The user's preferred "handle". A handle is like a Unix username. It contains only lower-case ASCII letters, digits, and underscores, and it never starts with a digit. The user can set their preferred handle in their account settings. This handle is NOT UNIQUE; it is only a hint from the user. Apps that use handles must decide for themselves whether they need unique handles and, if so, implement some mechanism to deal with duplicates (such as prompting the user to choose a different one, or just appending some digits). Apps should strongly consider using display names (
X-Sandstorm-Username) instead of handles. WARNING: A user can change their preferred handle at any time. Two users can have the same preferred handle. The preferred handle is just another form of display name. Do not use preferred handles as primary keys or for security; use
X-Sandstorm-User-Picture: The URL of the user's profile picture. The exact resolution of the picture is not specified, but assume it is optimized for a 64x64 or smaller viewport (i.e. the actual size is around 128x128 for high-DPI displays). Although profile pictures are normally square, it is recommended to use CSS
heightin order to avoid distorting a non-square picture. For logged-in users, this field is always present. The default value is an identicon generated from the user's ID.
X-Sandstorm-User-Pronouns: Indicates by which pronouns the user prefers to be referred. Possible values are
female(English: "she/her"), and
robot(English: "it"). If the header is not present, assume
neutral. The purpose of this header is to allow cleaner text in user interfaces.
Apps operating without sandstorm-http-bridge
It is possible to write a Sandstorm app that does not use
sandstorm-http-bridge! It can access authentication data by using
the Cap'n Proto raw Sandstorm API. We provide sample code for that in
repository on GitHub.
Defining permissions and roles
When sharing a grain, a user selects a bundle of permissions to grant. Such a bundle of permissions is called a role. Roles are intended to give users a more human-friendly handle on permissions and to steer users away from combinitions of permissions that might not make sense.
From Sandstorm's perspective, the meanings of permissions are completely opaque. Sandstorm merely tracks who is allowed to access which grain with which permissions. Sandstorm represents those permissions as a bit vector and leaves it up to the app to interpret those bits in an appropriate way. When a share takes place, Sandstorm records the role that was shared, but not the precise permissions, which are are computed on-the-fly every time the recipient of the share opens the grain. Therefore, if a later version of the app modifies the role definition, existing shares will be affected.
Apps define permissions and roles by providing a
UiView.ViewInfo to Sandstorm.
Apps that use
can specify a
ViewInfo value in the
Apps that do not use
can directly provide a
ViewInfo by implementing the
UiView.getViewInfo() Cap'n Proto method.
ViewInfo, permissions and roles are defined in lists of
values. Later versions of an app can always add more permissions or
roles, but it is important to never remove any element from these lists.
Instead, you can set the
obsolete field to
Here are some examples:
A sandstorm-pkgdef.capnp with no permissions defined.
A sandstorm-pkgdef.capnp with one permission defined.
A sandstorm-pkgdef.capnp with five permissions defined.
An implementation of
getViewInfo()in a C++ app that does not use
An implementation of
getViewInfo()in a Rust app that does not use