Skip to content

Current Cookie Implementation Faces CORS Issues #45

@A-lexisL

Description

@A-lexisL

Issue: Configure Cross-Subdomain Cookies for Authentication

Status: To Do

Context:
The Vue frontend is deployed on Cloudflare Pages at atlas.gcers.org, and the Django/DRF backend is deployed on a separate server at atlas-api.gcers.org. These are
different origins but the same site (gcers.org), so browser cookies can work across subdomains if both Django cookie settings and CORS/CSRF settings are configured
correctly.

The backend uses cookie-based authentication (sessionid) and also sets custom cookies such as temp_token. The frontend sends API requests using fetch(...,
{ credentials: "include" }), so the remaining work is to align backend cookie scope, CSRF behavior, and deployment configuration.

1. Backend Configuration (Django/DRF)

Update settings.py for the production environment:

  • ALLOWED_HOSTS = ["atlas-api.gcers.org"]
  • CORS_ALLOWED_ORIGINS = ["https://atlas.gcers.org"]
  • CORS_ALLOW_CREDENTIALS = True
  • CSRF_TRUSTED_ORIGINS = ["https://atlas.gcers.org"]

Configure shared cookie scope for subdomains:

  • SESSION_COOKIE_DOMAIN = ".gcers.org"
  • CSRF_COOKIE_DOMAIN = ".gcers.org"

Keep cookies secure in production:

  • SESSION_COOKIE_SECURE = True
  • CSRF_COOKIE_SECURE = True

Recommended explicit SameSite settings:

  • SESSION_COOKIE_SAMESITE = "Lax"
  • CSRF_COOKIE_SAMESITE = "Lax"

Notes:

  • atlas.gcers.org and atlas-api.gcers.org are cross-origin, but still same-site, so SameSite=Lax is appropriate and preferable to None.
  • CSRF_COOKIE_DOMAIN is required because the frontend reads csrftoken from document.cookie and sends it in the X-CSRFToken header.
  • Do not set CSRF_COOKIE_HTTPONLY = True, because the current frontend implementation needs to read the CSRF cookie in JavaScript.

If TLS is terminated by a reverse proxy, also ensure Django correctly detects HTTPS, for example:

  • SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")

This avoids Django mistakenly treating secure requests as HTTP and failing to mark cookies correctly.

2. Custom Cookie Configuration in Views

Any custom cookie that must survive cross-subdomain requests must be set with the parent domain explicitly.

For temp_token, update response.set_cookie(...) to include:

  • domain=".gcers.org"
  • secure=True
  • httponly=True
  • samesite="Lax"

Important: any matching delete_cookie(...) call must use the same cookie scope, especially the same domain and path, otherwise the browser may not delete the cookie
that was actually set.

So wherever temp_token is cleared, use matching deletion settings for:

  • cookie name: temp_token
  • domain=".gcers.org"
  • the same path used when setting it

3. Frontend Configuration (Vue / Cloudflare Pages)

Deployment configuration must use the backend’s absolute HTTPS origin:

4. CSRF Requirements

Because the frontend sends unsafe cross-origin requests from https://atlas.gcers.org to https://atlas-api.gcers.org, Django CSRF checks require both:

  • a readable csrftoken cookie scoped to .gcers.org
  • CSRF_TRUSTED_ORIGINS = ["https://atlas.gcers.org"]

Without CSRF_TRUSTED_ORIGINS, authenticated POST requests may fail even if the session cookie is present.

5. Verification Checklist

  • Local Mocking:
    • Edit hosts file: 127.0.0.1 app.test.local api.test.local.
    • Set SESSION_COOKIE_DOMAIN = ".test.local" in backend dev settings.
  • Checklist:
    1. Trigger login/token request.
    2. Check Network Tab: Confirm Set-Cookie header includes Domain=.test.local.
    3. Check Application Tab: Confirm Cookies are stored under the root domain, not the specific subdomain.
    4. Verify subsequent requests include Cookie in request headers.

6. Code Areas to Update

Backend:

  • website/settings.py
  • any production config source backing those settings (config.yaml, env vars, deployment secrets)
  • apps/auth/views.py for temp_token set_cookie(...)
  • apps/auth/views.py for matching delete_cookie(...)

Frontend:

  • Cloudflare Pages environment variable for VITE_API_BASE_URL

7. Summary of Required Changes

Required:

  • whitelist https://atlas.gcers.org in CORS
  • enable CORS_ALLOW_CREDENTIALS = True
  • trust https://atlas.gcers.org in CSRF
  • set SESSION_COOKIE_DOMAIN = ".gcers.org"
  • set CSRF_COOKIE_DOMAIN = ".gcers.org"
  • ensure all production cookies are Secure
  • set temp_token with domain=".gcers.org"
  • delete temp_token with matching domain/path
  • configure VITE_API_BASE_URL=https://atlas-api.gcers.org

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No fields configured for Bug.

    Projects

    Status

    Todo

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions