Signing people in
What your application calls to register, sign in, and stay signed in.
Stash runs an auth service for every project: your users, your passwords, your sessions. It is the same service a migration brings your existing users into, with their passwords intact.
This page is what your application has to call.
What moves and what changes
If you came from another platform, this is the one part of your application that needs editing.
| Your queries | Work unchanged. Point your client at the URL and key on your project's overview and carry on. |
| Your sign-in code | Changes. It calls Stash's auth instead, which is a handful of call sites rather than every query. |
The reason is not a missing feature. Stash's auth is its own service with its own API, and pretending to be somebody else's would mean matching their endpoints, their token format and their error shapes forever, including for applications that never used them. If that trade is blocking you, say so and it can be revisited.
Where it is
Every project has its own auth service, at its own address:
https://your-stash/api/auth/projects/<projectId>
Your project's id is in the address bar when you open it in the dashboard. On a local Stash the whole thing looks like this:
http://127.0.0.1:3010/api/auth/projects/2f7c1b6a-0000-4000-8000-000000000001
Sessions are per project. A token from one project is not accepted by another, and neither is a Stash dashboard login: your users are not Stash users.
Registering somebody
const auth = 'http://127.0.0.1:3010/api/auth/projects/<projectId>'
const response = await fetch(`${auth}/sign-up/email`, {
method: 'POST',
headers: { 'content-type': 'application/json' },
body: JSON.stringify({ name: 'Ada', email: 'ada@example.com', password: 'a passphrase' }),
})
const { token } = await response.json()
Signing in
const response = await fetch(`${auth}/sign-in/email`, {
method: 'POST',
headers: { 'content-type': 'application/json' },
body: JSON.stringify({ email: 'ada@example.com', password: 'a passphrase' }),
})
const { token } = await response.json()
Keep that token. It is what says which of your users a later request belongs to.
Using it with your data
Send it as a header alongside your project key:
await fetch(`${dataUrl}/rest/v1/orders?select=*`, {
headers: {
apikey: STASH_KEY,
authorization: `Bearer ${token}`,
},
})
A header rather than a cookie, because your application is on your own domain and a cross-site request carries no cookie.
This is the part that matters for row level security. With the header, the query
runs as that person and auth.uid() is their id, so policies written against
the signed-in user work exactly as they did before. Without it the query runs
anonymously, which is correct for a public read and is why a page that shows
nothing to a signed-in user is almost always a missing header.
Checking who somebody is
const response = await fetch(`${auth}/get-session`, {
headers: { authorization: `Bearer ${token}` },
})
const session = await response.json()
An expired or unknown token is not an error. It answers with no session, because "nobody is signed in" is an ordinary state and your application has to render something either way.
Signing out
await fetch(`${auth}/sign-out`, {
method: 'POST',
headers: { authorization: `Bearer ${token}` },
})
Passwords that came from somewhere else
A migration brings your users across with their password hashes, so everybody signs in with the password they already had and nobody gets a reset email. The first time each person signs in, Stash quietly rehashes their password with its own algorithm. They never notice, and nothing about it can fail their sign-in.
The migrate screen names anybody who could not come across before it writes anything, so you know in advance rather than hearing about it from them.
What is not here yet
Social sign-in, magic links and one-time codes. Email and password is what a migration brings across and what these endpoints cover. If you need one of the others, that is worth saying out loud rather than discovering here.
Found something wrong? Edit this page.