Skip to content

Feature: integrate Hanko auth login #538

Draft
andrea-chirillano wants to merge 26 commits intomainfrom
feature/login-hanko
Draft

Feature: integrate Hanko auth login #538
andrea-chirillano wants to merge 26 commits intomainfrom
feature/login-hanko

Conversation

@andrea-chirillano
Copy link
Copy Markdown
Collaborator

@andrea-chirillano andrea-chirillano commented Mar 26, 2026

This pull request requires in-depth review before merging.

This PR includes changes to the backend (Django), frontend (React/JS), infrastructure (Docker, nginx), and tests. Review carefully before approving.


Add Hanko SSO Authentication

Integrates Hanko SSO as an alternative to legacy OSM OAuth, enabling single sign-on across the HOT ecosystem via login.hotosm.org.

Key changes

  • New AUTH_PROVIDER setting (legacy | hanko) — default is legacy, existing deployments are unaffected
  • HankoAuthentication DRF backend added to DEFAULT_AUTHENTICATION_CLASSES (takes priority, falls back to token/OAuth2)
  • Onboarding flow to link existing OSM accounts or create new ones for first-time Hanko users
  • hotosm-auth web component (<hotosm-auth>) rendered in NavBar via HankoAuthButton.js
  • <hotosm/tool-menu> web component added to the layout (loaded from jsDelivr, fixed version)
  • Django upgraded from 3.2 → 4.2 LTS (required by hotosm-auth[django])
  • print() calls replaced with logging throughout api/views.py
  • Responsive navbar collapse added (mobile support)
  • Admin authorization now supports both modes: is_superuser (legacy) and ADMIN_EMAILS env var (Hanko)

New API Endpoints

Endpoint Method Description
/api/auth/me/ GET Current user info
/api/v1/auth/status/ GET Auth status + onboarding flag
/api/v1/auth/onboarding/ GET Callback from login service after OSM link
/api/admin/ Hanko→Django user mapping (admin panel)
/api/v1/ Hanko OSM OAuth routes (from hotosm_auth_django)

Legacy OAuth routes (/osm/, /o/, /authorized) are only registered when AUTH_PROVIDER=legacy.


New Dependencies

Package Location Notes
hotosm-auth[django]==0.2.10 Backend (PyPI) Hanko middleware, helpers, OSM views
tzdata Backend (PyPI) Required on minimal images (Python 3.9+)
@hotosm/hanko-auth@0.5.2 Frontend (jsDelivr CDN) Login web component
@hotosm/tool-menu@0.2.6 Frontend (jsDelivr CDN) HOT ecosystem nav menu

Required Environment Variables

Backend

Variable Required Example Description
AUTH_PROVIDER Yes hanko Set to hanko to enable SSO. Default: legacy
HANKO_API_URL Yes (Hanko) https://login.hotosm.org Hanko service URL
HANKO_PUBLIC_URL No same as above Public URL (defaults to HANKO_API_URL)
COOKIE_SECRET Yes (Hanko) <shared-secret> Must match the login service — coordinate with login team
COOKIE_DOMAIN Yes (Hanko) .hotosm.org Cookie domain — use .hotosm.org for cross-subdomain SSO
COOKIE_SECURE No true Defaults to not DEBUG
ADMIN_EMAILS No admin@hotosm.org Comma-separated list; replaces is_superuser in Hanko mode
RAW_DATA_API_PUBLIC_URL No https://api.rawdata.hotosm.org Public URL for frontend (falls back to RAW_DATA_API_URL)

Frontend (injected via Django template into window.*)

Variable Required Description
AUTH_PROVIDER Yes Must match backend
HANKO_URL Yes (Hanko) Hanko public URL — passed as hanko-url to <hotosm-auth>

How It Works

Legacy mode (default)

AUTH_PROVIDER=legacy — no changes, continues using OSM OAuth with access-token header.

Hanko mode

  1. User clicks login → redirected to login.hotosm.org
  2. Hanko sets a JWT cookie after authentication
  3. HankoAuthentication DRF backend validates the JWT cookie via hotosm_auth_django
  4. If a Django↔Hanko mapping exists → user is authenticated
  5. If no mapping → GET /api/v1/auth/status/ returns needs_onboarding: true → onboarding flow starts
  6. Onboarding: user chooses to link an existing OSM account (recovers data) or create a new one

Test Plan

  • Legacy auth continues working with AUTH_PROVIDER=legacy
  • Hanko login/logout flow works end-to-end
  • New user onboarding creates a Django account
  • Existing user onboarding recovers account via OSM link
  • GET /api/v1/auth/status/ returns correct authenticated and needs_onboarding values
  • Navbar shows correct user state in both modes
  • Protected routes redirect to login when unauthenticated
  • Worker dashboard access control works in both modes
  • Export creation (POST /api/v1/exports/) works with Hanko JWT cookie
  • Django 4.2 migration runs cleanly — no regressions from 3.2 upgrade
  • hotosm_auth_django app migrations apply correctly when AUTH_PROVIDER=hanko

Backward Compatibility

  • Default is legacy — no action required for existing deployments
  • Existing OSM OAuth users continue working unchanged
  • Switch to hanko when ready by setting the environment variables above

Deployment

The deploy is done manually via SSH. There is no automated pipeline — after the PR is merged, someone with server access must connect and deploy by hand.


Dependency & Django Version Update

Django has been upgraded from 3.2 → 4.2 LTS and several dependencies have been
updated to their latest compatible versions. These changes are required for two reasons:

  • Unit tests: the updated test suite relies on APIs and behaviors introduced in
    Django 4.2. Running tests against Django 3.2 will result in failures.
  • Security: Django 3.2 has no longer receives security
    patches. Upgrading to the 4.2 LTS branch ensures continued security support
    through April 2026.

@emi420 emi420 marked this pull request as draft March 27, 2026 17:02
Copy link
Copy Markdown
Collaborator

@emi420 emi420 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @andrea-chirillano ! I did my review before moving the PR to "Ready to review" so it's easier for other people to review it.

Thanks!

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @andrea-chirillano ! please remove this file, the branch feature/login_hanko will be deleted once merged so this file will not be used after that.

Copy link
Copy Markdown
Collaborator Author

@andrea-chirillano andrea-chirillano Mar 31, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi, the branch is necessary because that branch depends on the staging environment https://export.testlogin.hotosm.org/v3/


if not all:
queryset = queryset.filter(Q(user_id=user.id))

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why this change? it adds additional filters, could we revert it?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also realized they were unnecessary, and I've already reverted those changes.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove this file, it's only for testing on export.testlogin.hotosm.org and will not be used after the PR

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added it to gitignore

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file is for development right? if that's the case, please add a comment about it and move it to a docker folder

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added it to gitignore and move that Dockerfile into a docker folder.

@spwoodcock spwoodcock self-requested a review April 10, 2026 20:24
@spwoodcock
Copy link
Copy Markdown
Member

Thanks - I just saw this PR from the message on slack!

I have no idea how Export Tool is deployed in production, nor how we can test this PR for now, but once it's marked as ready for review, I can look into those things with dk 😄

@kshitijrajsharma
Copy link
Copy Markdown
Member

Thanks - I just saw this PR from the message on slack!

I have no idea how Export Tool is deployed in production, nor how we can test this PR for now, but once it's marked as ready for review, I can look into those things with dk 😄

its in a single ec2 instance in our aws ! Ideally we can swamp a quick stage server for export tool in a tiny instance ! I am happy to review once PR is ready !

@spwoodcock
Copy link
Copy Markdown
Member

Is it a systemd service or something, running the Python / Django server? I can't see any containerisation in the repo

@spwoodcock
Copy link
Copy Markdown
Member

Ah I literally just saw this dir!

https://github.com/hotosm/osm-export-tool/tree/main/ops/systemd

Assuming a few services all run in parallel, managed by systemd

@emi420
Copy link
Copy Markdown
Collaborator

emi420 commented Apr 10, 2026

We have a testing deployment:

https://export.testlogin.hotosm.org/

@kshitijrajsharma
Copy link
Copy Markdown
Member

kshitijrajsharma commented Apr 10, 2026

Yes systemd services, export tool isn't containerized yet ! Yarn builds the frontend !

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants