> **Building with AI coding agents?** Install the authstack plugin with one command. This equips your agent with accurate Scalekit implementation patterns.
>
> **Recommended**:
> ```bash
> npx @scalekit-inc/cli setup
> ```
>
> Global:
> ```bash
> npm install -g @scalekit-inc/cli
> scalekit setup
> ```
>
> Supports Claude Code, Cursor, GitHub Copilot, Codex + skills for 40+ agents.
> Skills: integrating-agentkit, implementing-saaskit, adding-mcp-oauth, implementing-modular-sso, implementing-scim-provisioning.
> [Full setup guide](https://docs.scalekit.com/dev-kit/build-with-ai/)

---

# Implement logout

Terminate user sessions across your application and Scalekit
When implementing logout functionality, you need to consider three session layers where user authentication state is maintained:

1. **Application session layer**: Your application stores session tokens (access tokens, refresh tokens, ID tokens) in browser cookies. You control this layer completely.

2. **Scalekit session layer**: Scalekit maintains a session for the user and stores their information. When users return to Scalekit's authentication page, their information is remembered for a smoother experience.

3. **Identity provider session layer**: When users authenticate with external providers (for example, Okta through enterprise SSO), those providers maintain their own sessions. Users won't be prompted to sign in again if they're already signed into the provider.

Clear the application session layer and invalidate the Scalekit session layer in a single logout endpoint.

> Image: Logout flow showing three session layers

1. ## Create a logout endpoint

   Create a `/logout` endpoint in your application that handles the complete logout flow: extracting the ID token, generating the Scalekit logout URL, clearing session cookies, and redirecting to Scalekit.

   
   ### Node.js

```html
[Log out](/logout)
```

`auth.router` already registered `GET /logout`.

   ### Next.js

```ts title="app/logout/route.ts"
import { auth } from '../../lib/auth';
export const GET = auth.createLogoutHandler();
```

```html
[Log out](/logout)
```

   
   
   ### Python

```html
[Log out](/logout)
```

`ScalekitAuth` already registered `GET /logout`.

   ### FastAPI

```html
[Log out](/logout)
```

`auth.install(app)` already registered `GET /logout`.

   
   
   ### Go

```go title="Gin"
     func logoutHandler(c *gin.Context) {
         // Step 1: Extract the ID token (needed for Scalekit logout)
         idToken, _ := c.Cookie("idToken")
         postLogoutRedirectURI := "http://localhost:3000/login"

         // Step 2: Generate the Scalekit logout URL (points to /oidc/logout endpoint)
         logoutURL, err := scalekitClient.GetLogoutUrl(LogoutUrlOptions{
             IdTokenHint: idToken,
             PostLogoutRedirectUri: postLogoutRedirectURI,
         })
         if err != nil {
             c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
             return
         }

         // Step 3: Clear all session cookies
         c.SetCookie("accessToken", "", -1, "/", "", true, true)
         c.SetCookie("refreshToken", "", -1, "/", "", true, true)
         c.SetCookie("idToken", "", -1, "/", "", true, true)  // Clear AFTER using it for logout URL

         // Step 4: Redirect to Scalekit to invalidate the session
         c.Redirect(http.StatusFound, logoutURL.String())
     }
     ```

      ### Java

```java title="Spring Boot"
@GetMapping("/logout")
public void logout(HttpServletRequest request, HttpServletResponse response) throws IOException {
    // Step 1: Extract the ID token (needed for Scalekit logout)
    String idToken = request.getCookies() != null ?
        Arrays.stream(request.getCookies())
            .filter(c -> c.getName().equals("idToken"))
            .findFirst()
            .map(Cookie::getValue)
            .orElse(null) : null;

    String postLogoutRedirectUri = "http://localhost:3000/login";

    // Step 2: Generate the Scalekit logout URL (points to /oidc/logout endpoint)
    LogoutUrlOptions options = new LogoutUrlOptions();
    options.setIdTokenHint(idToken);
    options.setPostLogoutRedirectUri(postLogoutRedirectUri);
    URL logoutUrl = scalekitClient.authentication().getLogoutUrl(options);

    // Step 3: Clear all session cookies with security attributes
    Cookie accessTokenCookie = new Cookie("accessToken", null);
    accessTokenCookie.setMaxAge(0);
    accessTokenCookie.setPath("/");
    accessTokenCookie.setHttpOnly(true);
    accessTokenCookie.setSecure(true);
    response.addCookie(accessTokenCookie);

    Cookie refreshTokenCookie = new Cookie("refreshToken", null);
    refreshTokenCookie.setMaxAge(0);
    refreshTokenCookie.setPath("/");
    refreshTokenCookie.setHttpOnly(true);
    refreshTokenCookie.setSecure(true);
    response.addCookie(refreshTokenCookie);

    Cookie idTokenCookie = new Cookie("idToken", null);
    idTokenCookie.setMaxAge(0);
    idTokenCookie.setPath("/");
    idTokenCookie.setHttpOnly(true);
    idTokenCookie.setSecure(true);
    response.addCookie(idTokenCookie);  // Clear AFTER using it for logout URL

    // Step 4: Redirect to Scalekit to invalidate the session
    response.sendRedirect(logoutUrl.toString());
}
```

    

   Session middleware clears `sk_session` and ends the Scalekit session. If you build logout yourself, extract the ID token before you clear cookies.

    ## Build it yourself — getLogoutUrl and clear cookies

Use this path when you do not use session middleware. Extract the ID token first. Then call `getLogoutUrl`. Then clear cookies. Then redirect the browser.

    ```javascript title="Express.js"
    app.get('/logout', (req, res) => {
      const idTokenHint = req.cookies.idToken;
      const postLogoutRedirectUri = 'http://localhost:3000/login';
      const logoutUrl = scalekit.getLogoutUrl({
        idTokenHint,
        postLogoutRedirectUri,
      });
      res.clearCookie('accessToken');
      res.clearCookie('refreshToken');
      res.clearCookie('idToken');
      res.redirect(logoutUrl);
    });
    ```

    ```python title="Flask"
    from flask import request, redirect, make_response
    from scalekit.common.scalekit import LogoutUrlOptions

    @app.route('/logout')
    def logout():
        id_token = request.cookies.get('idToken')
        logout_url = scalekit_client.get_logout_url(
            LogoutUrlOptions(
                id_token_hint=id_token,
                post_logout_redirect_uri='http://localhost:3000/login',
            )
        )
        response = make_response(redirect(logout_url))
        response.set_cookie('accessToken', '', max_age=0)
        response.set_cookie('refreshToken', '', max_age=0)
        response.set_cookie('idToken', '', max_age=0)
        return response
    ```

   > note: Why must logout be a browser redirect?
>
> You must redirect to the `/oidc/logout` endpoint using a **browser redirect**, not through an API call. Redirecting the browser to Scalekit's logout URL ensures the session cookie is automatically sent with the request, allowing Scalekit to correctly identify and end the user's session.

2.  ## Configure post-logout redirect URL

    After users log out, Scalekit redirects them to the URL you specify in the `post_logout_redirect_uri` parameter. This URL must be registered in your Scalekit dashboard under **Dashboard > Authentication > Redirects > Post Logout URL**.

    Scalekit only redirects to URLs from your allow list. This prevents unauthorized redirects and protects your users. If you need different redirect URLs for different applications, you can register multiple post-logout URLs in your dashboard.

> tip: Logout security checklist
>
> Session middleware: send a browser navigation to `/logout`. Register the post-logout URL in the dashboard.
>
> If you build logout yourself: extract the ID token before you clear cookies, then redirect the browser to the URL from `getLogoutUrl`.

## Common logout scenarios

## Which endpoint should I use for logout?

Use `GET /logout` from session middleware. That handler redirects the browser to Scalekit's `/oidc/logout` endpoint and clears `sk_session`.

If you build logout yourself, call `getLogoutUrl` and redirect the browser to the returned URL. Do not call `/oidc/logout` with `fetch`.

## Why must logout be a browser redirect?

You need to route to the `/oidc/logout` endpoint through a **browser redirect**, not with an API request. Redirecting the browser to Scalekit's logout URL ensures the session cookie is sent automatically, so Scalekit can correctly locate and end the user's session.

**❌ Doesn't work - API call from frontend:**
```javascript
fetch('https://your-env.scalekit.dev/oidc/logout', {
  method: 'POST',
  body: JSON.stringify({ id_token_hint: idToken })
});
// Session cookie is NOT included, Scalekit can't identify the session
```

**✅ Works - Browser redirect:**
```javascript
const logoutUrl = scalekit.getLogoutUrl({
  idTokenHint: idToken,
  postLogoutRedirectUri,
});
window.location.href = logoutUrl;
// Browser includes session cookies automatically
```

**Why:** Your user session is stored in an HttpOnly cookie. API requests from JavaScript or backend servers don't include this cookie, so Scalekit can't identify which session to terminate.

## Session not clearing after logout?

If clicking login after logout bypasses the login screen and logs you back in automatically, check the following:

1. **Verify the logout method** - Open browser DevTools → Network tab and trigger logout:
   - ✅ Type should show **"document"** (navigation)
   - ❌ Type should **NOT** show "fetch" or "xhr"
   - Check that the `Cookie` header is present in the request

2. **Check post-logout redirect URI** - Ensure it's registered in **Dashboard > Authentication > Redirects > Post Logout URL**.


---

## 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 |
