passbolt/passbolt_api · error · Cake\Http\Exception\ForbiddenException

Simultaneous SCIM and session authentication is not…

Error message

Simultaneous SCIM and session authentication is not permitted.

What it means

This ForbiddenException is thrown by the SCIM auth middleware when an HTTP request reaches a SCIM endpoint while already carrying a valid session authentication (browser cookie). Passbolt's SCIM API is designed exclusively for bearer-token (SCIM authentication service) access, so the middleware deliberately swaps the container's AuthenticationService for ScimAuthenticationService and rejects any request where a server-side session is already valid. This prevents ambiguous identity resolution where a request could be simultaneously treated as a logged-in user session and a SCIM client.

Solutions

  1. Log out of the passbolt web UI (clear the session cookie) in the client making the SCIM request, or make SCIM calls from a non-browser client (curl, Postman, SDK) that does not send session cookies
  2. Ensure the SCIM client sends only the Authorization: Bearer <token> header and does not forward cookies; use a separate domain/subdomain or cookie-free path for SCIM automation
  3. If writing tests or integrations, authenticate against SCIM endpoints using a dedicated SCIM request token (obtained via the SCIM settings endpoints) rather than the logged-in session
  4. Review any reverse-proxy or middleware that merges browser sessions into API requests and strip the session cookie for /scim/ routes

Example fix

// before (browser fetch while logged in - session cookie is sent)
fetch('/scim/v2/abc123/Users', { headers: { Authorization: 'Bearer ' + token } });

// after (server-side curl, no cookies)
curl -H "Authorization: Bearer $SCIM_TOKEN" https://passbolt.example.com/scim/v2/abc123/Users
Defensive patterns

Strategy: validation

Validate before calling

if (document.cookie.includes('passbolt_session')) {
  throw new Error('Cannot call SCIM endpoints from a session-authenticated browser context.');
}

Type guard

function isScimSafeRequest(headers: Headers): boolean {
  return headers.has('Authorization') && headers.get('Authorization')!.startsWith('Bearer ') && !hasSessionCookie();
}

Try / catch

try {
  const res = await fetch(scimUrl, { headers: { Authorization: `Bearer ${token}` }, credentials: 'omit' });
  if (res.status === 403) throw new ScimSessionConflictError(await res.text());
} catch (e) { /* handle ScimSessionConflictError / network errors */ }

Prevention

When it happens

Trigger: Any request to /scim/v2/... routes that includes both a SCIM bearer token header and a valid PHP session cookie. The middleware's assertNotSessionAuthenticated() fetches the SessionAuthenticationService from the DI container, calls authenticate($request), and throws when isValid() is true. The most common concrete case: an admin who is logged into the passbolt web UI in the same browser (same domain) calls SCIM endpoints from scripts or a REST client using that browser's cookies.

Common situations: Calling SCIM API endpoints directly from the browser (e.g. testing /scim/v2/settingId/Users in the address bar or via fetch/XHR in the web UI console while logged in); proxies or applications that forward the user's cookies together with the SCIM Authorization header; automated tests that reuse an authenticated browser session against SCIM endpoints.

Understand the failure class

Related errors


AI-assisted analysis of passbolt/passbolt_api@31c1bbc10f (2026-09-17). Data as JSON: /api/errors/7461ff76ae2f690c. Report an issue: GitHub.

Appendix: source

Thrown at plugins/PassboltEe/Scim/src/Middleware/ScimAuthMiddleware.php:93

    /**
     * @param \Cake\Http\ServerRequest $request server request
     * @param \Cake\Core\ContainerInterface $container container
     * @return void
     * @throws \Psr\Container\ContainerExceptionInterface
     * @throws \Psr\Container\NotFoundExceptionInterface
     * @throws \Cake\Http\Exception\ForbiddenException if the user is logged in via session
     */
    private function assertNotSessionAuthenticated(ServerRequest $request, ContainerInterface $container): void
    {
        /** @var \Authentication\AuthenticationServiceInterface $authenticationService */
        $authenticationService = $container->get(AuthenticationServiceInterface::class);
        if (!($authenticationService instanceof SessionAuthenticationService)) {
            return;
        }
        $isUserSessionAuthenticated = $authenticationService->authenticate($request)->isValid();
        if ($isUserSessionAuthenticated) {
            throw new ForbiddenException(__('Simultaneous SCIM and session authentication is not permitted.'));
        }
    }
}

View on GitHub (pinned to 31c1bbc10f)