Protect Your Endpoints

Add authentication to your API endpoints with JWT tokens and role-based access.

Protect Your Endpoints

Not every endpoint should be public. You can require authentication so only logged-in users (or users with specific roles) can access certain routes.

The endpoint editor with the JWT authentication option
Enable JWT authentication on any endpoint

Require authentication

Open the endpoint

Go to Endpoints and click the endpoint you want to protect.

Set authentication to JWT

In the endpoint editor, change Authentication from None to JWT.

Save

Click Save. The endpoint now requires a valid token in the Authorization header.

Clients must include the token like this:

Authorization: Bearer eyJhbGciOiJIUzI1NiJ9...

If the token is missing or invalid, Spala returns a 401 Unauthorized response automatically.

How JWT tokens work

JWT (JSON Web Tokens) is a simple way to handle login sessions:

1. A user logs in with their email and password via a public /api/auth/login endpoint
2. Your login function verifies the credentials and creates a token using a Generate Auth Token step
3. The client stores the token and sends it with every request
4. Protected endpoints automatically verify the token before running the function

Good to know

Tokens contain user data (like id, email, role) and expire after a set time (e.g., 24 hours). No database lookup is needed to verify them.

Frontend session contract

Frontend builders need the exact session contract generated for the project. At handoff time, document:

| Field | Example |
| --- | --- |
| Login route | POST /api/auth/login |
| Signup route | POST /api/auth/register |
| Token field | token, accessToken, or data.token |
| Protected header | Authorization: Bearer USER_JWT |
| Expiry | 24h, 7d, or project-specific |
| Refresh route | POST /api/auth/refresh, if implemented |
| Logout behavior | Clear local token, revoke server session, or both |
| Cookie mode | credentials: "include" if the project uses cookie sessions |
| CSRF header | Required only when the project implements CSRF protection |

If no refresh route is documented, treat token expiry as a login-required event. If the project uses cookie sessions, browser CORS must also allow credentials and the frontend must use credentials: "include".

Cookie-session request example:

const response = await fetch(`${SPALA_API_BASE_URL}/api/me`, {
  credentials: "include",
  headers: {
    "X-CSRF-Token": csrfToken,
  },
});

The CSRF header name, cookie attributes, same-site policy, and logout behavior are project-specific. Document them in the generated API docs or frontend handoff packet before asking an external frontend developer to integrate cookie auth.

Cookie checklist for browser clients:

| Field | What to confirm |
| --- | --- |
| SameSite | Lax, Strict, or None; cross-site cookies require SameSite=None |
| Secure | Required for cross-site HTTPS cookies |
| Domain/path | Which frontend and API hosts receive the cookie |
| CSRF source | Meta tag, cookie, endpoint, or generated page value |
| Logout | Whether logout expires the cookie, revokes the server session, or both |

Built-in endpoint auth vs manual verification

Use endpoint-level JWT authentication when an endpoint should be protected before its function runs. This is the usual production path for user-facing APIs because Spala rejects missing or invalid tokens automatically and exposes decoded auth data to the function.

Use a manual Verify JWT step inside a function only when the endpoint intentionally accepts mixed public/authenticated traffic, needs to verify a secondary token, or is implementing a custom auth handshake such as a realtime connection or webhook signature.

Access the logged-in user in a function

When an endpoint has JWT authentication enabled, the decoded token data is available in your function:

vars.auth.userId   // The user's ID
vars.auth.email    // The user's email
vars.auth.role     // The user's role, such as "admin" or "user"

Use this to personalize responses or restrict actions:

// Only return the current user's cases
Database Query: SELECT * FROM cases WHERE client_id = vars.auth.userId

Add role-based access

For admin-only endpoints, add a role check at the start of your function:

// Step 1: Check role
If/Else: vars.auth.role !== 'admin'
  True branch: Return { error: "Admin access required" }, Status: 403

// Step 2: Continue with admin logic...

Which endpoints to protect?

| Endpoint              | Auth   | Why                              |
|----------------------|--------|----------------------------------|
| POST /api/auth/login   | None   | Users need to log in             |
| POST /api/auth/register| None   | Users need to sign up            |
| GET /products      | None   | Anyone can browse                |
| POST /products     | JWT    | Only logged-in users can create  |
| DELETE /products/:id| JWT   | Only admins can delete           |
| GET /orders        | JWT    | Users see only their own orders  |

Never store plain-text passwords

Always use the Hash Password step (bcrypt) before saving passwords, and Verify Password when verifying during login.

Create an Endpoint
/endpoints/creating-endpoints
Set up endpoints step by step
Inputs & Outputs
/endpoints/inputs-outputs
Handle request data
User Authentication Guide
/guides/user-auth
Full login and registration setup