changemaker.lite/PRODUCTION_403_FIX.md

6.2 KiB

Production 403 Errors - Root Cause & Fix

Diagnosis Summary

Issue: All API endpoints returning 302 redirects to Pangolin authentication page Root Cause: Pangolin tunnel resources configured with authentication enabled (should be "Not Protected") Status: CORS configuration FIXED | Pangolin resources NEEDS MANUAL FIX


What Was Fixed

CORS Configuration (COMPLETED)

File: /home/bunker-admin/changemaker.lite/.env

Changes applied:

# Changed from development to production
NODE_ENV=production

# Added production domain to CORS whitelist
CORS_ORIGINS=http://app.betteredmonton.org,https://app.betteredmonton.org,http://localhost:3000,http://localhost

API container restarted: Done


What Still Needs Manual Fix

Pangolin Resource Authentication (REQUIRES MANUAL ACTION)

Problem: Resources are configured with authentication, causing 302 redirects to auth page.

Evidence:

$ curl -I https://api.betteredmonton.org/api/health
HTTP/2 302
location: https://pangolin.bnkserve.org/auth/resource/68488f80-b055-41ea-bc1b-0ab905fb8a53?redirect=...

Fix Required: Change authentication setting for ALL Pangolin resources to "Not Protected"


Step-by-Step Fix Instructions

1. Log in to Pangolin Dashboard

URL: https://api.bnkserve.org (remove /v1 from API URL)

2. Navigate to Resources

Dashboard → ResourcesPublic

3. Edit Each Resource

For EACH of these critical resources:

  • app.betteredmonton.org (Admin GUI + Public Pages)
  • api.betteredmonton.org (Main API)
  • media.betteredmonton.org (Media API)
  • db.betteredmonton.org (NocoDB)
  • docs.betteredmonton.org (MkDocs)
  • code.betteredmonton.org (Code Server)
  • git.betteredmonton.org (Gitea)
  • n8n.betteredmonton.org (n8n)
  • grafana.betteredmonton.org (Grafana)
  • listmonk.betteredmonton.org (Listmonk)
  • qr.betteredmonton.org (Mini QR)
  • home.betteredmonton.org (Homepage)

Most critical (fix these first):

  1. api.betteredmonton.org - Main API (all endpoints fail without this)
  2. app.betteredmonton.org - Admin GUI (login page won't work)
  3. media.betteredmonton.org - Media API (video library features)

4. Change Authentication Setting

For each resource:

  1. Click Edit (pencil icon)
  2. Find Authentication or Access Policy section
  3. Change from "Protected" or "Authenticated" to:
    • "Not Protected" OR
    • "Public Access" OR
    • "No Authentication" (exact wording depends on Pangolin UI version)
  4. Click Save

5. Verify Fix

After changing authentication settings, test each endpoint:

Test API:

curl https://api.betteredmonton.org/api/health
# Expected: {"status":"healthy","checks":{"database":"ok","redis":"ok"}}
# NOT: 302 redirect

Test Public Campaigns:

curl https://api.betteredmonton.org/api/campaigns/public
# Expected: JSON array of campaigns
# NOT: 302 redirect

Test Admin GUI: Visit https://app.betteredmonton.org in browser

  • Should see login page
  • NO redirect to Pangolin auth page

Why This Happened

  1. Pangolin resources default to "Protected" - requires manual change to "Not Protected"
  2. Manual setup process - automated setup was removed, so resources must be configured manually
  3. No API enforcement - Pangolin API doesn't enforce "Not Protected" when creating resources programmatically

Resource Configuration Reference

Correct settings for ALL resources:

  • Protocol: HTTPS (SSL enabled)
  • Target: nginx:80 (all services route through nginx)
  • Authentication: Not Protected ← THIS IS CRITICAL
  • SSL/TLS: Enabled

Troubleshooting

Still seeing 302 redirects after changing settings?

  1. Clear browser cache - old redirects may be cached
  2. Try incognito/private window
  3. Wait 30-60 seconds - Pangolin may need time to update routing
  4. Check resource status - ensure resource shows as "Active" in Pangolin dashboard
  5. Verify target - should point to nginx:80 (not individual service ports)

API works locally but not via tunnel?

Confirm:

  • Newt container is running: docker compose ps newt
  • Newt logs show connection: docker compose logs newt --tail 50
  • PANGOLIN_SITE_ID, PANGOLIN_NEWT_ID, PANGOLIN_NEWT_SECRET are set in .env
  • Nginx is running: docker compose ps nginx

Health endpoint works but other endpoints fail?

Check in this order:

  1. Test public endpoints (no auth): /api/campaigns/public, /api/shifts/public
  2. Test protected endpoints with valid JWT: /api/campaigns, /api/users
  3. Check auth store in browser DevTools: localStorage should have auth-storage with tokens
  4. Verify JWT secrets haven't changed (would invalidate existing tokens)

Post-Fix Verification Checklist

After changing Pangolin resource authentication to "Not Protected":


Summary

What was done:

  1. Updated .env with production CORS origins
  2. Set NODE_ENV to production
  3. Restarted API container
  4. Verified API works locally

What you need to do:

  1. Log in to Pangolin dashboard at https://api.bnkserve.org
  2. Edit each resource and set Authentication to "Not Protected"
  3. Verify endpoints no longer return 302 redirects
  4. Test application is fully functional

Time estimate: 5-10 minutes to update all 12 resources


Contact

If you encounter issues after following these steps:

  • Check Pangolin documentation: https://pangolin.bnkserve.org/docs (if available)
  • Review Newt container logs: docker compose logs newt
  • Verify nginx routing: docker compose logs nginx | grep betteredmonton.org