@hotosm/hanko-auth
v0.5.4
Published
Web component for HOTOSM SSO authentication with Hanko and OSM integration
Downloads
480
Readme
Web Component: <hotosm-auth>
Lit-based web component for HOTOSM SSO authentication with Hanko and OpenStreetMap integration.
Installation
# npm
npm install @hotosm/hanko-auth
# pnpm
pnpm add @hotosm/hanko-auth
# yarn
yarn add @hotosm/hanko-authQuick Start
Import the component
import "@hotosm/hanko-auth";Use in HTML
<hotosm-auth
hanko-url="https://login.hotosm.org"
show-profile="true"
></hotosm-auth>React Example
import { useEffect, useRef } from "react";
import "@hotosm/hanko-auth";
export function AuthButton({ hankoUrl, onLogin }) {
const ref = useRef<HTMLElement>(null);
useEffect(() => {
const el = ref.current;
const handler = (e: CustomEvent) => onLogin(e.detail.user);
el?.addEventListener("hanko-login", handler);
return () => el?.removeEventListener("hanko-login", handler);
}, [onLogin]);
return <hotosm-auth ref={ref} hanko-url={hankoUrl} osm-required />;
}Attributes
Core
| Attribute | Type | Default | Description |
| - | - | - | - |
| hanko-url | string | window.location.origin | Login service URL |
| base-path | string | "" | Base URL for OSM OAuth endpoints |
| auth-path | string | /api/auth/osm | OSM auth endpoints path |
Behavior
| Attribute | Type | Default | Description |
| - | - | - | - |
| osm-required | boolean | false | Require OSM connection |
| osm-scopes | string | "read_prefs" | OSM scopes (space-separated) |
| auto-connect | boolean | false | Auto redirect to OSM OAuth |
| verify-session | boolean | false | Verify session on return flow |
Display
| Attribute | Type | Default | Description |
| - | - | - | - |
| show-profile | boolean | false | Show full profile |
| display-name | string | "" | Override display name |
| lang | string | "en" | Locale (e.g., "en", "es", "fr"), fallback "en" |
| button-variant | string | "filled" | filled, outline, or plain |
| button-color | string | "primary" | primary, neutral, or danger |
| display | string | "default" | default (avatar) or bar mode |
Redirects
| Attribute | Type | Default | Description |
| ----------------------- | ------ | ------- | -------------------------- |
| redirect-after-login | string | "" | URL after successful login |
| redirect-after-logout | string | "" | URL after logout |
Cross-app
| Attribute | Type | Default | Description |
| ------------------- | ------ | ------- | ----------------------------- |
| mapping-check-url | string | "" | URL to check user mapping |
| app-id | string | "" | App identifier for onboarding |
Events
The component dispatches the following custom events:
| Event | Detail | When |
| --------------- | ---------------------- | --------------------------- |
| hanko-login | { user: HankoUser } | User logged in |
| osm-connected | { osmData: OSMData } | OSM account linked |
| osm-skipped | {} | User skipped OSM connection |
| auth-complete | {} | Auth flow complete |
| logout | {} | User logged out |
Event Handling Example
const auth = document.querySelector("hotosm-auth");
auth.addEventListener("hanko-login", (e) => {
console.log("Logged in:", e.detail.user.email);
});
auth.addEventListener("osm-connected", (e) => {
console.log("OSM connected:", e.detail.osmData.osm_username);
});
auth.addEventListener("logout", () => {
console.log("User logged out");
window.location.href = "/";
});Flash Prevention (localStorage cache)
On remount (e.g. React navigation), the component checks localStorage for a
cached user under the key hotosm-auth-user. If found, it skips the loading
spinner and renders immediately with the cached user.
The component reads from this key but does not write to it. The host app is responsible for keeping it in sync:
// Write on login
auth.addEventListener("hanko-login", (e) => {
localStorage.setItem("hotosm-auth-user", JSON.stringify(e.detail.user));
});
// Clear on logout
auth.addEventListener("logout", () => {
localStorage.removeItem("hotosm-auth-user");
});If the key is absent (first visit, after logout, or cleared storage), the component falls back to its normal loading flow - no change in behavior.
Usage Modes
Header Mode (default)
Shows a compact login button in the header:
<header>
<hotosm-auth
hanko-url="https://login.hotosm.org"
redirect-after-login="/"
></hotosm-auth>
</header>Button Styling
Customize the login button appearance with button-variant and button-color:
<!-- Filled primary button (default) -->
<hotosm-auth hanko-url="https://login.hotosm.org"></hotosm-auth>
<!-- Outline button -->
<hotosm-auth
hanko-url="https://login.hotosm.org"
button-variant="outline"
button-color="primary"
></hotosm-auth>
<!-- Plain text button -->
<hotosm-auth
hanko-url="https://login.hotosm.org"
button-variant="plain"
button-color="neutral"
></hotosm-auth>
<!-- Filled danger button -->
<hotosm-auth
hanko-url="https://login.hotosm.org"
button-variant="filled"
button-color="danger"
></hotosm-auth>Bar Mode
Shows a full-width bar with avatar, email, and chevron arrow (ideal for mobile drawers/menus):
<hotosm-auth
hanko-url="https://login.hotosm.org"
display="bar"
redirect-after-login="/"
></hotosm-auth>Profile Mode
Shows full authentication form (for login pages):
<hotosm-auth
hanko-url="https://login.hotosm.org"
show-profile
osm-required
auto-connect
redirect-after-login="https://portal.hotosm.org"
></hotosm-auth>Styling
The component uses Shadow DOM and can be customized using CSS custom properties.
CSS Custom Properties
Whole component
| Property | Description | Default |
| - | - | - |
| --font-family | Font family for all text | system-ui |
| --font-weight | Font weight for all text | 500 |
Login button
| Property | Description | Default |
| - | - | - |
| --login-btn-margin | Margin around the login button | 0 |
| --login-btn-padding | Padding inside button | x-small ... |
| --login-btn-bg-color | Button bg color | var(--hot-color-primary-1000) |
| --login-btn-hover-bg-color | Hover bg | primary-900 |
| --login-btn-border-radius | Button radius | radius-medium |
| --login-btn-text-color | Button text color | white |
| --login-btn-text-size | Button text size | var(--hot-font-size-medium) |
| --login-btn-font-family | Button font family | from --font-family |
| --login-btn-font-weight | Button font weight | from --font-weight |
Example
hotosm-auth {
/* Whole component */
--font-family: 'Inter', sans-serif;
--font-weight: 400;
/* Login button overrides */
--login-btn-margin: 8px;
--login-btn-padding: 12px 24px;
--login-btn-bg-color: #d73f3f;
--login-btn-hover-bg-color: #b83333;
--login-btn-border-radius: 8px;
--login-btn-text-color: #ffffff;
--login-btn-text-size: 16px;
--login-btn-font-family: 'Arial', sans-serif;
--login-btn-font-weight: 700;
}Configuration
Hanko URL Detection
The component detects the Hanko URL in the following priority order:
hanko-urlattribute<meta name="hanko-url" content="...">tagwindow.HANKO_URLglobal variablewindow.location.origin(fallback)
<!-- Option 1: Attribute -->
<hotosm-auth hanko-url="https://login.hotosm.org"></hotosm-auth>
<!-- Option 2: Meta tag -->
<meta name="hanko-url" content="https://login.hotosm.org" />
<hotosm-auth></hotosm-auth>
<!-- Option 3: JavaScript -->
<script>
window.HANKO_URL = "https://login.hotosm.org";
</script>
<hotosm-auth></hotosm-auth>