How Clients Authenticate
RESTHeart Cloudπ§ Configuration
What You’ll Learn
In this guide, you’ll learn how to:
-
Authenticate using Basic Authentication with username and password
-
Understand how the Authorization header works
-
Obtain and use OAuth 2.0 access tokens
-
Check user credentials and roles
-
Avoid browser authentication popups
By the end, you’ll understand how clients authenticate with RESTHeart and how to implement authentication in your applications.
|
Note
|
In all examples below:
The interactive examples on this page can automatically substitute these values. |
β‘ Setup Guide
To run the examples on this page, you need a RESTHeart instance.
Option 1: Use RESTHeart Cloud (Recommended)
The fastest way to get started is with RESTHeart Cloud. Create a free service in minutes:
-
Sign up at cloud.restheart.com
-
Create a free API service
-
Set up your root user following the Root User Setup guide
-
Use the configuration panel above to set your service URL and credentials
|
Tip
|
All code examples on this page will automatically use your configured RESTHeart Cloud credentials. |
Option 2: Run RESTHeart Locally
If you prefer local development, follow the Setup Guide to install RESTHeart on your machine.
|
Note
|
Local instances run at http://localhost:8080 with default credentials admin:secret
|
Introduction
Clients can authenticate passing credentials via the different authentication schemes handled by restheart-security. This section shows how clients can authenticate using the simple basic authentication, a standard method for an HTTP user agent to provide a username and password when making a request.
Some examples
Here’s how to authenticate with basic credentials:
cURL
curl -i --user [BASIC-AUTH] -X GET [RESTHEART-URL]/
HTTPie
http -a [BASIC-AUTH] GET [RESTHEART-URL]/
JavaScript
const username = 'your-username';
const password = 'your-password';
const credentials = btoa(`${username}:${password}`);
fetch('[RESTHEART-URL]/', {
method: 'GET',
headers: {
'Authorization': `Basic ${credentials}`
}
})
.then(response => response.json())
.then(data => {
console.log('Retrieved data:', data);
})
.catch(error => console.error('Error:', error));
Basic Authentication for dummies
Basic Authentication requires the client to send its credentials with the Authorization request header.
The value of the Authorization request header must be: Basic base64(<userid> + ':' + <password>)
In other words:
-
userid and password are combined into a string "userid:password". Note the colon between userid and password (userid cannot contain the ":" character).
-
The resulting string is base 64 encoded
-
The string "Basic " (note the space) is then put before the encoded string.
Authentication Token
RESTHeart v9 provides a standards-compliant OAuth 2.0/2.1 token endpoint. Once a client has authenticated (Basic Auth, an OAuth grant, or a delegated provider login), it needs a token back to use for subsequent requests β RESTHeart offers three ways to hand that token over, and picking the right one is the core decision in designing a sign-in flow.
Choosing How to Deliver the Token
RESTHeart offers three ways to hand a token to a client, each with a different security trade-off. There’s no universally "best" option β pick based on your architecture.
Quick decision guide:
-
Frontend and backend share a registrable domain (same-site β e.g.
app.example.comcallingapi.example.com)?
β UsePOST /token/cookie. It’s the simplest option: the browser attaches the cookie automatically, the token is never exposed to JavaScript, and none of the cross-origin caveats below apply. -
Otherwise (cross-origin frontend), does the sign-in step end in a real browser navigation rather than a
fetch()call (OAuth-provider callback, email-verification link, magic link)?
β UseGET /token/redirect(since 9.5). There’s no JSON response for your JavaScript to read in this case, so the token has to travel via the redirect itself. -
Otherwise (cross-origin, and your own JavaScript makes the request) β login forms, token refresh, any SPA that can’t rely on a same-site cookie:
β UsePOST/GET /tokenand hold the token in memory (notlocalStorage). This is the general default for cross-origin SPAs, and the only option that works reliably in Safari, where third-party cookies are blocked outright regardless ofSameSite.
| Pros | Cons | Use it when | |
|---|---|---|---|
Token in body ( |
Works identically in every browser, no cross-origin restrictions of any kind; simplest to reason about; no ambient credential means near-zero CSRF risk (a forged cross-site request can’t include a token it doesn’t know) |
The token is JavaScript-accessible wherever the client stores it (memory, localStorage, …) β if the page has an XSS vulnerability, the token can be read and exfiltrated. Mitigate with short TTLs and in-memory-only storage (never |
The frontend itself initiates the request ( |
HttpOnly cookie ( |
Never readable by JavaScript at all β immune to XSS token theft (though an XSS can still ride the ambient cookie to perform actions as the user) |
Doesn’t work reliably cross-origin: |
Frontend and API share a registrable domain (true same-site), and you want the session to survive without any client-side token handling at all |
Redirect + fragment ( |
Works in every browser like the body option (no cookie involved at all); purpose-built for flows that must end in a real navigation (OAuth callbacks, etc.) |
Same XSS-exposure profile as the body option, plus the token is briefly visible in the URL/browser history until the frontend clears the fragment |
The authentication step itself ends in a server-side redirect, not a |
The three flows
Token in body β the client makes the request directly and reads the token from the JSON response:
sequenceDiagram
participant C as Client
participant R as RESTHeart
C->>R: POST /token (Basic Auth)
R-->>C: 200, JSON body { token, ... }
Note over C: hold token in memory
C->>R: GET /resource (Authorization: Bearer <token>)
R-->>C: 200
HttpOnly cookie β the browser handles the cookie automatically on same-site requests, no client-side token handling at all:
sequenceDiagram
participant C as Client
participant R as RESTHeart
C->>R: POST /token/cookie (Basic Auth)
R-->>C: 200, Set-Cookie: <JWT> (HttpOnly)
C->>R: GET /resource (cookie sent automatically)
R-->>C: 200
Redirect + fragment β used when authentication itself ends in a real browser navigation rather than a fetch() call (e.g. after an OAuth-provider round trip):
sequenceDiagram
participant C as Browser
participant R as RESTHeart
Note over C,R: some flow ending in a real navigation, e.g. OAuth callback
C->>R: GET /token/redirect (already authenticated)
R-->>C: 307, Location: https://app.example.com/callback#access_token=...
Note over C: frontend JS reads location.hash,<br/>stores token, clears the fragment
C->>R: GET /resource (Authorization: Bearer <token>)
R-->>C: 200
Synergy with originVetoer
originVetoer rejects requests whose Origin header isn’t allowlisted β the standard CSRF defense for cookie-based sessions, since a browser attaches a cookie automatically regardless of which site triggered the request.
-
Cookie-based auth genuinely needs
originVetoer(or equivalent Origin validation): without it, any website could trigger state-changing requests using a victim’s ambient session cookie. -
Token-in-body and redirect+fragment don’t rely on cookies, so
originVetoerisn’t strictly required for CSRF purposes with those β a forged request from another site simply has no token to send. But precisely because there’s no cookie in play, there’s no cross-origin trade-off to protect (noSameSiterelaxation, no legitimate cross-site cookie flow that a strict whitelist could break) β this makesoriginVetoera genuinely low-cost opportunity here: whitelisting the exact origin(s) allowed to call/tokenand/token/redirectrestricts who can even attempt to obtain a token in the first place (e.g. blocking credential-stuffing or brute-force attempts issued from arbitrary/unauthorized origins), on top of whatever’s already true for authenticated requests.
originVetoer itself supports a per-request whitelist override since RESTHeart 9.5 (override-origin-whitelist, see Other Security Plugins) β the same multi-tenant use case /token/redirect’s `override-redirect-url addresses: one RESTHeart instance serving many services, each needing its own allowed origin(s)/redirect target.
The OAuth 2.0 / 2.1 page has the complete API reference for each endpoint:
-
POST /tokenβ password, client_credentials, and authorization_code grants -
POST /token/cookieβ HttpOnly cookie for browser applications -
GET /token/redirect(since 9.5) β redirect-based handoff for browser-navigation flows -
Authorization Code + PKCE flow (OAuth 2.1, RFC 7636)
-
Authorization Server Metadata discovery (RFC 8414)
-
Protected Resource Metadata (RFC 9728)
Legacy Token Management (Automatic Injection)
|
Note
|
This is the legacy token management approach. For new applications, use the OAuth 2.0 /token endpoint.
|
RESTHeart can also automatically inject auth tokens into response headers. The default configuration includes the tokenBasicAuthMechanism and the rndTokenManager.
With those plugins enabled, when a request is successfully authenticated, an auth token is generated by the Token Manager and included in every subsequent responses.
the tokenBasicAuthMechanism allows to authenticate the client using the auth token; the auth token is used as a temporary password in the basic authentication scheme. This means that the Authorization request header can either be calculated from the the Auth-Token itself:
Authorization: Basic base64(<userid> + ':' + <password>) or Authorization: Basic base64(<userid> + ':' + <auth-token>)
Auth token information are passed in the following response headers:
Auth-Token: 6a81d622-5e24-4d9e-adc0-e3f7f2d93ac7
Auth-Token-Location: /tokens/user@si.com
Auth-Token-Valid-Until: 2015-04-16T13:28:10.749Z
|
Note
|
the URI in the Auth-Token-Location header: the client can issue a GET request to obtain information about token or a DELETE request to invalidate it. Of course clients can only request their own tokens (otherwise response code will be 403 Forbidden). |
Token Management Examples
To get information about your auth token:
cURL
curl -i --user [BASIC-AUTH] -X GET [RESTHEART-URL]/tokens/userid
HTTPie
http GET [RESTHEART-URL]/tokens/userid Authorization:"Basic [BASIC-AUTH]"
JavaScript
const username = 'your-username';
const password = 'your-password';
const credentials = btoa(`${username}:${password}`);
fetch('[RESTHEART-URL]/tokens/userid', {
method: 'GET',
headers: {
'Authorization': `Basic ${credentials}`
}
})
.then(response => response.json())
.then(data => {
console.log('Token information:', data);
})
.catch(error => console.error('Error:', error));
To invalidate your auth token:
cURL
curl -i --user [BASIC-AUTH] -X DELETE [RESTHEART-URL]/tokens/userid
HTTPie
http DELETE [RESTHEART-URL]/tokens/userid Authorization:"Basic [BASIC-AUTH]"
JavaScript
const username = 'your-username';
const password = 'your-password';
const credentials = btoa(`${username}:${password}`);
fetch('[RESTHEART-URL]/tokens/userid', {
method: 'DELETE',
headers: {
'Authorization': `Basic ${credentials}`
}
})
.then(response => {
if (response.ok) {
console.log('Token invalidated successfully');
} else {
console.error('Failed to invalidate token:', response.status);
}
})
.catch(error => console.error('Error:', error));
|
Tip
|
The Authentication Token is a very important feature when you are developing a web application. Since every request needs to include the credentials, you need to store them either in a cookie or (better) in the session storage. The sign-in form can check the credentials using the actual password; if it succeeds, the auth token can be stored and used. |
|
Warning
|
Pay attention to the authentication token in case of multi-node deployments (horizontal scalability). In this case, you need to either disable it or use a load balancer with the sticky session option or a different Token Manager implementation. |
The rndTokenManager can be configured as follows (note option TTL the auth token Time To Live in minutes):
rndTokenManager:
ttl: 15
srv-uri: /tokens
Suggested way to check credentials
The default restheart configuration file sets up the useful service roles, bound to /roles/<userid>
Here’s how to check credentials using the roles endpoint:
cURL
curl -i --user [BASIC-AUTH] -X GET [RESTHEART-URL]/roles/userid
HTTPie
http GET [RESTHEART-URL]/roles/userid Authorization:"Basic [BASIC-AUTH]"
JavaScript
const username = 'your-username';
const password = 'your-password';
const credentials = btoa(`${username}:${password}`);
fetch('[RESTHEART-URL]/roles/userid', {
method: 'GET',
headers: {
'Authorization': `Basic ${credentials}`
}
})
.then(response => response.json())
.then(data => {
console.log('User roles:', data);
})
.catch(error => console.error('Error:', error));
The possible response codes of the request GET /roles/<userid>
are:
-
401 Unauthorized missing or wrong credentials
-
403 Forbidden the userid in the URL does not match the one in the Authorization header
-
200 OK credentials match; the following response document is sent back:
{
"authenticated": true,
"roles": [
"USER"
]
}
Of course, if the request succeeds, the client gets back the auth token as well.
|
Note
|
It is easy to check the user credentials from a login form with this handler: in case the client gets back 200, they match and the auth token can be stored for further request; otherwise passed credentials are wrong. |
How to avoid the basic authentication popup in browsers
With basic authentication, browsers can show a awful login popup window and this is not what you usually want.
What happens behind the scene, is that the server sends
the WWW-Authenticate response header that actually leads to it.
You can avoid RESTHeart to actually send this header avoiding the popup
login window altogether, either specifying
the No-Auth-Challenge request header or using
the noauthchallenge query parameter. In this case, RESTHeart will just
respond with 401 Unauthorized in case of missing or wrong
credentials.
|
Tip
|
This feature together with the authentication token, allows you to implement a form based authentication experience on top of the simple and effective basic authentication mechanism. |