# Copyright (c) 2023-present Plane Software, Inc. and contributors # SPDX-License-Identifier: AGPL-3.0-only # See the LICENSE file for details. # Python imports import os # Django imports from django.views import View from django.contrib.auth import logout from django.http import HttpResponseRedirect from django.utils import timezone # Module imports from plane.authentication.utils.host import user_ip, base_host from plane.db.models import User # binarybeachio fork addition. When set, the SPA's /auth/sign-out/ form-POST # (apps/web/core/services/auth.service.ts) gets 302'd here instead of back to # the app root. The platform bridge's /logout endpoint clears the # oauth2-proxy `_bb_oauth2` cookie AND back-channels Zitadel's end_session, # so signing out from inside Plane now propagates to the edge — without it, # the user lands back on / with the Zitadel session still alive at the edge, # auto-redirects through plane-signin-redirect → bridge handoff → trusted # sign-in, and is silently re-logged-in as the same identity. # # Read at request time so dashboard env-var changes don't require a rebuild. # See binarybeachio/docs/services/auth-bridge/session-debrief-2026-05-04-edge-validation-and-logout.md # §B "Bundle with each rollout". _BB_LOGOUT_REDIRECT_URL_ENV = "BB_LOGOUT_REDIRECT_URL" class SignOutAuthEndpoint(View): def post(self, request): # Get user try: user = User.objects.get(pk=request.user.id) user.last_logout_ip = user_ip(request=request) user.last_logout_time = timezone.now() user.save() # Log the user out logout(request) except Exception: pass bb_logout_url = os.environ.get(_BB_LOGOUT_REDIRECT_URL_ENV) or "" target = bb_logout_url or base_host(request=request, is_app=True) response = HttpResponseRedirect(target) # Clear the edge-identity marker cookie alongside the session. The # SessionMiddleware will delete the session-id cookie on its own once # request.session.is_empty() (Django logout() flushes it), but the # marker has no equivalent owner — clear it explicitly here. response.delete_cookie("_bb_edge_sub", path="/") return response