Skip to content

Current Cookie Implementation Faces CORS Issues #45

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

    Projects

    Status
    Todo

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions