Authentication β
The S-Launch API supports two authentication methods:
- OAuth2 Password Bearer β username/password exchange that yields a short-lived access token and a refresh cookie. Best for interactive sessions and first-party clients.
- API Key Header β a long-lived
X-API-Keyheader value. Best for server-to-server and automation use cases.
Most endpoints accept either method (the OpenAPI security block lists both). The notable exceptions are the OAuth2 endpoints themselves and the bootstrap activation endpoint, which are unauthenticated.
OAuth2 β Password Flow β
Endpoint β
POST /api/login/access-token
Exchanges a username and password for an access token. Request body is form-urlencoded, not JSON.
Request body β Body_Authentication-Login
| Field | Type | Required | Notes |
|---|---|---|---|
username | string | yes | User's login. |
password | string | yes | User's password. |
grant_type | string | no | If supplied, must be password. |
scope | string | no | Space-separated scopes to request (default: empty). |
client_id | string | no | Reserved for future use. |
client_secret | string | no | Reserved for future use. |
Response 200 β LoginResponse
{
"access_token": "eyJhbGciOiβ¦",
"token_type": "bearer"
}The server also sets a slaunch_refresh_cookie HTTP-only cookie that is used by Refresh Access Token.
Errors: 401 (bad credentials), 422 (malformed request) β see Conventions βΊ Errors.
curl β
curl -X POST "https://<tenant>.s-launch.com/api/login/access-token" \
-H "Content-Type: application/x-www-form-urlencoded" \
-c cookies.txt \
--data-urlencode "username=alice@example.com" \
--data-urlencode "password=hunter2"The -c cookies.txt flag captures the refresh cookie for later use.
JavaScript (fetch) β
const body = new URLSearchParams({
username: 'alice@example.com',
password: 'hunter2',
})
const res = await fetch('https://<tenant>.s-launch.com/api/login/access-token', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
credentials: 'include', // accept the refresh cookie
body,
})
const { access_token } = await res.json()credentials: 'include' is required for the refresh cookie to be stored by the browser.
Using the Access Token β
Send the access token on every subsequent request as a Bearer token:
curl "https://<tenant>.s-launch.com/api/self" \
-H "Authorization: Bearer eyJhbGciOiβ¦"await fetch('https://<tenant>.s-launch.com/api/self', {
headers: { Authorization: `Bearer ${access_token}` },
})Refresh Access Token β
Endpoint β
POST /api/login/refresh-token
Issues a new access token using the slaunch_refresh_cookie set during login. There is no request body β the refresh credential travels in a cookie.
Cookie
| Name | Required | Notes |
|---|---|---|
slaunch_refresh_cookie | yes | Set by POST /api/login/access-token. |
Response 200 β LoginResponse (same shape as login).
Errors: 401 (cookie missing or revoked), 422.
curl β
curl -X POST "https://<tenant>.s-launch.com/api/login/refresh-token" \
-b cookies.txt -c cookies.txtJavaScript (fetch) β
const res = await fetch('https://<tenant>.s-launch.com/api/login/refresh-token', {
method: 'POST',
credentials: 'include',
})
const { access_token } = await res.json()The browser automatically attaches the refresh cookie when credentials: 'include' is set; the server may rotate the cookie on success.
Logout β
Endpoint β
GET /api/logout
Invalidates the current session and clears the refresh cookie.
Required scope: none beyond a valid session (any authenticated user can log out).
Response 200 β empty body.
curl β
curl "https://<tenant>.s-launch.com/api/logout" \
-H "Authorization: Bearer eyJhbGciOiβ¦" \
-b cookies.txt -c cookies.txtJavaScript (fetch) β
await fetch('https://<tenant>.s-launch.com/api/logout', {
headers: { Authorization: `Bearer ${access_token}` },
credentials: 'include',
})Google OAuth β
A two-step flow for "Sign in with Google":
Start β
GET /api/login/google/start
Returns the Google authorization URL the user should be redirected to. The browser-side client typically just navigates to the returned URL.
Exchange β
GET /api/login/google/exchange?assertion=<jwt>
Verifies the JWT assertion returned by Google and creates a session β same response shape and refresh-cookie behavior as the password flow.
Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
assertion | string | yes | The JWT assertion returned by Google's IdP. |
Response 200 β { access_token, token_type } plus a slaunch_refresh_cookie cookie.
Errors: 401 (invalid assertion), 422.
Browser snippet β
// 1. Kick off the flow.
const { url } = await fetch('https://<tenant>.s-launch.com/api/login/google/start')
.then(r => r.json())
window.location.href = url
// 2. After Google redirects back with an assertion in the URL, exchange it:
const params = new URLSearchParams(window.location.search)
const res = await fetch(
`https://<tenant>.s-launch.com/api/login/google/exchange?assertion=${params.get('assertion')}`,
{ credentials: 'include' },
)
const { access_token } = await res.json()API Key β
API keys are the simplest authentication mechanism β set a single header on each request:
curl "https://<tenant>.s-launch.com/api/store/asset/" \
-H "X-API-Key: sla_live_β¦"Keys are minted and scoped via the API Keys admin endpoints. Each key carries an explicit scope set; requests fail with 403 when a key lacks the scopes a given endpoint requires.
Token Lifetime & Rotation β
- Access tokens are short-lived (default lifetime is configured server-side via Configuration).
- The refresh cookie is HTTP-only and tied to a session; sessions can be inspected and revoked via Sessions (admin) or your own session list at
GET /api/self/sessions. - Refreshing rotates the access token. Refresh tokens may also rotate; always trust the latest
Set-Cookiefrom/api/login/refresh-token.
