> **Building with AI coding agents?** If you're using an AI coding agent, install the official Scalekit plugin. It gives your agent full awareness of the Scalekit API — reducing hallucinations and enabling faster, more accurate code generation.
>
> - **Claude Code**: `/plugin marketplace add scalekit-inc/claude-code-authstack` then `/plugin install <auth-type>@scalekit-auth-stack`
> - **GitHub Copilot CLI**: `copilot plugin marketplace add scalekit-inc/github-copilot-authstack` then `copilot plugin install <auth-type>@scalekit-auth-stack`
> - **Codex**: run the bash installer, restart, then open Plugin Directory and enable `<auth-type>`
> - **Skills CLI** (Windsurf, Cline, 40+ agents): `npx skills add scalekit-inc/skills --list` then `--skill <skill-name>`
>
> `<auth-type>` / `<skill-name>`: `agent-auth`, `full-stack-auth`, `mcp-auth`, `modular-sso`, `modular-scim` — [Full setup guide](https://docs.scalekit.com/dev-kit/build-with-ai/)

---

# Web application

Implement login, token management, and logout in your web application using the Authorization Code flow. Web applications have a backend server that can securely store a `client_secret`, allowing them to authenticate directly with Scalekit's token endpoint. This guide covers initiating login from your backend, exchanging authorization codes for tokens, managing sessions with secure cookies, and implementing logout.

:::tip
[**Check out the example apps on GitHub**](https://github.com/scalekit-inc/multiapp-demo) to see Web, SPA, Desktop, and Mobile apps sharing a single Scalekit session.
:::

## Prerequisites

Before you begin, ensure you have:

- A Scalekit account with an environment configured
- Your environment URL (`ENV_URL`), e.g., `https://yourenv.scalekit.com`
- A web application registered in Scalekit with `client_id` and `client_secret` ([Create one](/authenticate/fsa/multiapp/manage-apps))
- At least one redirect URL configured in **Dashboard > Developers > Applications > [Your App] > Redirects**

## High-level flow

```d2
shape: sequence_diagram

User
"Web app (frontend)"
"Web app (backend)"
Scalekit

User -> "Web app (frontend)": Click "Login"
"Web app (frontend)" -> "Web app (backend)": GET /login
"Web app (backend)" -> Scalekit: Redirect to /oauth/authorize
Scalekit -> "Web app (backend)": Redirect to /callback with code + state
"Web app (backend)" -> Scalekit: POST /oauth/token
Scalekit -> "Web app (backend)": access_token, refresh_token, id_token
"Web app (backend)" -> "Web app (frontend)": Set session cookies + redirect
```

## Step-by-step implementation

1. ## Initiate login or signup

   Initiate login by redirecting the user to Scalekit's hosted login page from your backend. Generate and store a `state` parameter before redirecting to validate the callback.

   ```sh
   <ENV_URL>/oauth/authorize?
     response_type=code&
     client_id=<CLIENT_ID>&
     redirect_uri=<CALLBACK_URL>&
     scope=openid+profile+email+offline_access&
     state=<RANDOM_STATE>
   ```
**Why web apps use client_secret:** Web applications store the `client_secret` on the backend server where it cannot be accessed by browsers or end users. This allows your backend to authenticate directly with Scalekit's token endpoint without needing PKCE. Never expose the `client_secret` to the frontend or include it in client-side JavaScript.

   For detailed parameter definitions, see [Initiate signup/login](/authenticate/fsa/implement-login).

2. ## Handle the callback and complete login

   After authentication, Scalekit redirects the user back to your callback endpoint with an authorization `code` and the `state` you sent.

   Your backend must:

   - Validate the returned `state` matches what you stored — this confirms the response is for your original request and prevents CSRF attacks
   - Handle any error parameters before processing
   - Exchange the authorization code for tokens using your `client_secret`

   ```sh
   POST <ENV_URL>/oauth/token
   Content-Type: application/x-www-form-urlencoded

   grant_type=authorization_code&
   client_id=<CLIENT_ID>&
   client_secret=<CLIENT_SECRET>&
   code=<CODE>&
   redirect_uri=<CALLBACK_URL>
   ```

   ```json
   {
     "access_token": "...",
     "refresh_token": "...",
     "id_token": "...",
     "expires_in": 299
   }
   ```
**Authorization codes expire after one use:** Authorization codes are single-use and expire quickly (approximately 10 minutes). If you attempt to reuse a code or it expires, start a new login flow to obtain a fresh authorization code.

3. ## Manage sessions and token refresh

   Store tokens in secure cookies and validate the access token on each request. When access tokens expire, use the refresh token to obtain new ones without requiring the user to re-authenticate.

   **Token roles**

   - **Access token** — Short-lived token (default 5 minutes) for authenticated API requests
   - **Refresh token** — Long-lived token to obtain new access tokens
   - **ID token** — JWT containing user identity claims; required for logout

   Store tokens in secure, HttpOnly cookies with appropriate path scoping to limit exposure.

   When an access token expires, request new tokens:

   ```sh
   POST <ENV_URL>/oauth/token
   Content-Type: application/x-www-form-urlencoded

   grant_type=refresh_token&
   client_id=<CLIENT_ID>&
   client_secret=<CLIENT_SECRET>&
   refresh_token=<REFRESH_TOKEN>
   ```

   Validate access tokens by verifying:

   - Token signature using Scalekit's public keys (JWKS endpoint)
   - `iss` matches your Scalekit environment URL
   - `aud` includes your `client_id`
   - `exp` and `iat` are valid timestamps

   Public keys for signature verification:

   ```sh
   <ENV_URL>/keys
   ```

4. ## Implement logout

   Clear your application session and redirect to Scalekit's logout endpoint to invalidate the shared session.

   Your logout endpoint must:

   - Extract the ID token before clearing cookies
   - Clear application session cookies
   - Redirect the browser to Scalekit's logout endpoint

   ```sh
   <ENV_URL>/oidc/logout?
     id_token_hint=<ID_TOKEN>&
     post_logout_redirect_uri=<POST_LOGOUT_REDIRECT_URI>
   ```
**Logout must be a browser redirect:** Use a browser redirect to the `/oidc/logout` endpoint, not an API call. The redirect ensures Scalekit's session cookie is sent with the request, allowing Scalekit to identify and terminate the correct session.

   Configure [backchannel logout](/guides/dashboard/redirects/#back-channel-logout-url) URLs to receive notifications when a logout is performed from another application sharing the same user session.

## Handle errors

When authentication fails, Scalekit redirects to your callback URL with error parameters instead of an authorization code:

```sh showLineNumbers=false wrap
/callback?error=access_denied&error_description=User+denied+access&state=<STATE>
```

Check for errors before processing the authorization code:

- Check if the `error` parameter exists in the URL
- Log the `error` and `error_description` for debugging
- Display a user-friendly message
- Provide an option to retry login

Common error codes:

| Error | Description |
|-------|-------------|
| `access_denied` | User denied the authorization request |
| `invalid_request` | Missing or invalid parameters |
| `server_error` | Scalekit encountered an unexpected error |

## (Optional) Use Scalekit Management APIs

In addition to handling user authentication, web applications can call Scalekit's Management APIs from the backend. These APIs allow your application to interact with Scalekit-managed resources such as users, organizations, memberships, and roles.

Typical use cases include:

- Fetching the currently authenticated user
- Listing organizations the user belongs to
- Managing organization membership or roles

Management APIs are Scalekit-owned APIs intended for server-side use only. Enable Management API access in your application:

1. Go to **app.scalekit.com**
2. Navigate to **Developers > Applications**
3. Select your **Web Application**
4. Enable **Allow Scalekit Management API Access**
**Management API access is only available for web applications:** This option is only available for web applications because they can securely store credentials. When enabled, your backend can authenticate to Scalekit's Management APIs using the application's credentials. These calls are independent of end-user access tokens and are designed for trusted, server-side workflows.

## What's next

- [Configure backchannel logout](/guides/dashboard/redirects/#back-channel-logout-url) to receive notifications when a user logs out from another app
- [Set up a custom domain](/guides/custom-domain) for your authentication pages
- [Add enterprise SSO](/authenticate/auth-methods/enterprise-sso/) to support SAML and OIDC with your customers' identity providers

---

## More Scalekit documentation

| Resource | What it contains | When to use it |
|----------|-----------------|----------------|
| [/llms.txt](/llms.txt) | Structured index with routing hints per product area | Start here — find which documentation set covers your topic before loading full content |
| [/llms-full.txt](/llms-full.txt) | Complete documentation for all Scalekit products in one file | Use when you need exhaustive context across multiple products or when the topic spans several areas |
| [sitemap-0.xml](https://docs.scalekit.com/sitemap-0.xml) | Full URL list of every documentation page | Use to discover specific page URLs you can fetch for targeted, page-level answers |
