DEV Community

Alex Spinov
Alex Spinov

Posted on

Hanko Has a Free API — Here's How to Add Passkey Authentication Without Passwords

Passwords are dying. Apple, Google, and Microsoft are pushing passkeys. GitHub supports them. Shopify requires them for staff. A developer told me: 'We removed password login entirely. Support tickets for forgotten passwords dropped to zero.'

What Hanko Offers for Free

Hanko Cloud free tier:

  • 10,000 monthly active users
  • Passkeys — biometric login (Face ID, fingerprint, Windows Hello)
  • Email login — passcode-based (no passwords)
  • Social login — Google, Apple, GitHub, etc.
  • Pre-built UI components — drop-in auth pages
  • User management — profiles, sessions, MFA
  • REST API — full programmatic access
  • Open source — self-host for unlimited

Quick Start

<!-- Drop-in Hanko Auth component -->
<script type="module" src="https://cdn.jsdelivr.net/npm/@nicekid1/hanko-elements/dist/elements.js"></script>

<hanko-auth api="https://YOUR_HANKO_API_URL"></hanko-auth>
Enter fullscreen mode Exit fullscreen mode

That's it. Users can now login with passkeys or email passcodes.

React Integration

import { Hanko } from '@nicekid1/hanko-elements';
import { useEffect, useState } from 'react';

const hankoApi = process.env.NEXT_PUBLIC_HANKO_API_URL!;

export default function LoginPage() {
  useEffect(() => {
    import('@nicekid1/hanko-elements').then(({ register }) => {
      register(hankoApi).catch(console.error);
    });
  }, []);

  return <hanko-auth api={hankoApi} />;
}

// Check if user is logged in
export function useUser() {
  const [user, setUser] = useState(null);

  useEffect(() => {
    const hanko = new Hanko(hankoApi);
    hanko.user.getCurrent()
      .then(setUser)
      .catch(() => setUser(null));
  }, []);

  return user;
}
Enter fullscreen mode Exit fullscreen mode

REST API

# Get current user (with session cookie)
curl 'https://YOUR_HANKO_API_URL/users/me' \
  -H 'Cookie: hanko=SESSION_TOKEN'

# List users (admin)
curl 'https://YOUR_HANKO_API_URL/users' \
  -H 'Authorization: Bearer ADMIN_API_KEY'

# Create user
curl -X POST 'https://YOUR_HANKO_API_URL/users' \
  -H 'Authorization: Bearer ADMIN_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{"emails": [{"address": "alice@example.com", "is_primary": true}]}'

# Get user's passkeys
curl 'https://YOUR_HANKO_API_URL/users/USER_ID/webauthn_credentials' \
  -H 'Authorization: Bearer ADMIN_API_KEY'

# Delete user
curl -X DELETE 'https://YOUR_HANKO_API_URL/users/USER_ID' \
  -H 'Authorization: Bearer ADMIN_API_KEY'
Enter fullscreen mode Exit fullscreen mode

Server-Side Verification (Node.js)

import * as jose from 'jose';

const JWKS_URL = `${process.env.HANKO_API_URL}/.well-known/jwks.json`;

async function verifySession(token: string) {
  const JWKS = jose.createRemoteJWKSet(new URL(JWKS_URL));

  const { payload } = await jose.jwtVerify(token, JWKS);
  return {
    userId: payload.sub,
    email: payload.email
  };
}

// Express middleware
app.use(async (req, res, next) => {
  const token = req.cookies.hanko;
  if (!token) return res.status(401).json({ error: 'Not authenticated' });

  try {
    req.user = await verifySession(token);
    next();
  } catch {
    res.status(401).json({ error: 'Invalid session' });
  }
});
Enter fullscreen mode Exit fullscreen mode

Why Passkeys Over Passwords

Passkeys Passwords
Phishing-proof Phishable
No password to forget Reset emails
Biometric (instant) Type + remember
No password database to breach Breach risk
Built into OS/browser Need password manager

Self-Hosted

docker run -d \
  -p 8000:8000 \
  -e DATABASE_URL=postgres://user:pass@db:5432/hanko \
  ghcr.io/nicekid1/hanko/hanko:latest
Enter fullscreen mode Exit fullscreen mode

Building secure web apps? Check out my web scraping actors on Apify — secure data collection.

Need passwordless auth? Email me at spinov001@gmail.com.

Top comments (0)