Skip to content
codeheadsystemsPublic

About

passkey-centric drop-in authentication layer. AI built, experimental, not for production

Topics

Resources

Contributing

Security policy

Stars

2 stars

Watchers

1 watching

Forks

Latest commit

 

History

342 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

pk-auth

pk-auth CI passkeys-browser mutation score

pk-auth is a production-grade, passkeys-first authentication template for the JVM. It ships as a reusable library set that drops into a Spring Boot, Dropwizard, or Micronaut application. The core is framework-neutral, and the host's user and credential storage is a plug-in SPI.

Maven Central

All modules share one version and the com.codeheadsystems group id.

Artifact ID Version Description
pk-auth-core Maven Central: pk-auth-core Framework-neutral SPIs, DTOs, and ceremony service.
pk-auth-jwt Maven Central: pk-auth-jwt HS256/ES256 JWT issuance + validation (Nimbus JOSE+JWT).
pk-auth-admin-api Maven Central: pk-auth-admin-api Framework-neutral admin service (list/rename/delete passkeys, etc.).
pk-auth-backup-codes Maven Central: pk-auth-backup-codes Argon2id-hashed one-time backup codes.
pk-auth-magic-link Maven Central: pk-auth-magic-link Single-use email magic-link tokens.
pk-auth-otp Maven Central: pk-auth-otp 6-digit SMS OTP codes for phone verification.
pk-auth-refresh-tokens Maven Central: pk-auth-refresh-tokens Rotating refresh tokens with family-based replay defence. (1.1.0)
pk-auth-persistence-jdbi Maven Central: pk-auth-persistence-jdbi JDBI 3 + Flyway + Postgres SPI implementations.
pk-auth-persistence-dynamodb Maven Central: pk-auth-persistence-dynamodb AWS SDK v2 DynamoDB Enhanced SPI implementations (single-table core + separate users table).
pk-auth-testkit Maven Central: pk-auth-testkit FakeAuthenticator, in-memory SPIs, and fixtures for tests.
pk-auth-spring-boot-starter Maven Central: pk-auth-spring-boot-starter Spring Boot 4 / Spring Security 7 auto-configure.
pk-auth-dropwizard Maven Central: pk-auth-dropwizard Dropwizard 5 ConfiguredBundle + Dagger 2 wiring.
pk-auth-micronaut Maven Central: pk-auth-micronaut Micronaut 4 @Factory + controllers + JWT filter.

Features

  • WebAuthn registration and assertion ceremonies, including multi-passkey enrolment and conditional UI, backed by WebAuthn4J.
  • A stateless JWT mint at the end of authentication (HS256, configurable TTL). With the 1.1.0 AccessTokenStore SPI, the mint is a stateful access token that is revocable before its exp.
  • Per-audience JWT TTL dispatch via TokenTtlPolicy, so web, cli, and mobile clients can carry different access-token lifetimes from a single issuer.
  • Rotating refresh tokens with family-based replay defence (1.1.0). POST /auth/refresh is one ceremony and one row per rotation, with motif-style atomic mark-and-insert and family scorch on detected replay. The browser SDK's PkAuthClient.refresh() returns a typed result sum and never throws on 401. See ADR 0013.
  • Account admin: list, rename, and delete passkeys; regenerate view-once backup codes; account summary.
  • Alternative-flow modules: backup codes, magic-link email verification, and phone OTP verification, each behind a host-implementable SPI.
  • A framework-neutral admin service that every adapter mounts at the same paths, so the same TypeScript SDK drives all three.
  • Persistence options: in-memory (testkit), JDBI + Postgres with Flyway migrations, or DynamoDB single-table. The JDBI migrations ship as a required core set (classpath:db/migration/core) and an opt-in example users set (classpath:db/migration/example-users) used only with JdbiUserLookup; the operator guide gives the Flyway configuration for each.
  • A zero-dependency browser SDK (@pk-auth/passkeys-browser) covering both ceremony and admin operations, published on npm (npm install @pk-auth/passkeys-browser). Its version tracks the pk-auth server release it speaks to.
flowchart LR
  Browser["Browser SPA<br/>(@pk-auth/passkeys-browser SDK)"] -- HTTPS / JSON --> Adapter["pk-auth-{spring-boot,dropwizard,micronaut}<br/>mounts /auth/**"]
  Adapter --> Core["pk-auth-core<br/>(framework-neutral)"]
  Core --> Persistence["pk-auth-persistence-{jdbi,dynamodb}<br/>or testkit (in-memory)"]
  Core --> Alt["backup-codes / magic-link / otp"]
Loading

Related documents:

Demo

The Spring Boot demo is the fastest path to a working server:

./gradlew :examples:spring-boot-demo:run

The demo serves at http://localhost:8080, to be opened in a passkey-capable browser (Chrome, Edge, Safari, Firefox 130+). The single-page UI exercises every flow:

  1. Registration of an account; the platform authenticator (Touch ID, Windows Hello, security key) handles the ceremony.
  2. Sign-in, which returns a JWT; the page decodes its claims at the bottom.
  3. Listing, renaming, and deleting passkeys; the demo enforces the last-credential guard.
  4. Regeneration of backup codes (view-once) and a remaining-count check.
  5. Email verification via magic link and phone verification via OTP.

Magic-link tokens and OTP codes are written to the server console (the testkit ships LoggingEmailSender and LoggingSmsSender). Copying them from the Gradle log back into the form completes the verification flows.

Two other demos exist for the other adapters, with the same UI over a different framework:

./gradlew :examples:dropwizard-demo:run    # Jersey + Dropwizard 5
./gradlew :examples:micronaut-demo:run     # Netty + Micronaut 4

Only one demo can run at a time, because all three bind to port 8080.

Layout

pk-auth-core/                  # framework-neutral ceremony engine + SPIs
pk-auth-jwt/                   # HS256 JWT mint + validate, AccessTokenStore, TokenTtlPolicy
pk-auth-backup-codes/          # alt flow: Argon2id-hashed backup codes
pk-auth-magic-link/            # alt flow: email magic-link verification
pk-auth-otp/                   # alt flow: phone OTP verification
pk-auth-refresh-tokens/        # rotating refresh tokens with family-based replay defense
pk-auth-admin-api/             # framework-neutral admin operations
pk-auth-persistence-jdbi/      # SPI impls on JDBI + Postgres + Flyway
pk-auth-persistence-dynamodb/  # SPI impls on AWS DynamoDB Enhanced
pk-auth-testkit/               # FakeAuthenticator + in-memory SPIs
pk-auth-spring-boot-starter/   # adapter: Spring Boot 4 / Spring Security 7
pk-auth-dropwizard/            # adapter: Dropwizard 5 Bundle + Dagger 2
pk-auth-micronaut/             # adapter: Micronaut 4 controllers + filter
clients/passkeys-browser/      # TypeScript SDK (ESM + CJS)
examples/                      # runnable demos for each adapter
docs/                          # ADRs, operator guide, threat model

Build

./gradlew check          # full lint + test + coverage gate
./gradlew clean build test

Requirements:

  • JDK 21. Gradle's toolchain fetches one if none is present.
  • Node 22.22.2 or later, and npm, for the browser SDK build, which Gradle invokes automatically (./gradlew :buildPasskeysBrowserSdk).

Optional, needed only for the JDBI and DynamoDB persistence integration tests and the Playwright end-to-end suites:

  • Docker. Testcontainers starts Postgres and DynamoDB Local.
  • Chrome. Playwright drives a CDP virtual WebAuthn authenticator.

Status

The 1.0.0 release cut the stable baseline. The current development line is the 2.x -SNAPSHOT named by version in gradle.properties, which is the authoritative source. The 1.1 line added per-audience JWT TTLs, the AccessTokenStore (stateful access tokens), the UserDeletionService fan-out, and the pk-auth-refresh-tokens module (rotating refresh tokens with family-based replay defence). Releases 1.2 and 1.3 followed with per-framework admin toggles and supply-chain hardening.

See CHANGELOG.md for the full delta and docs/stability.md for the versioning policy and the list of SPI surfaces. The full build and end-to-end suites pass. The test classpath includes the testkit's FakeAuthenticator, so registration and assertion ceremonies exercise the real WebAuthn4J verifier without a browser.

Transactional boundaries

pk-auth does not require host SPIs to share a transactional context. At ceremony finish, ChallengeStore.takeOnce is consumed before CredentialRepository.save. If the save fails, the user restarts the ceremony from the beginning, and a new challenge is issued. Challenges are short-lived (5-minute default TTL), so a forced restart is acceptable, and it avoids distributed-transaction complexity across heterogeneous SPI implementations. See docs/transactional-semantics.md for full details.

Licence

MIT. See LICENSE.

DISCLAIMER from the human

For this project development, I played the role of product manager and architect, but let Claude write all the code. If you do not like AI generated code, then you will want to ignore this project.

This project is open-source and is not based on any novel ideas. It's a way to provide a standardized approach to your project authentication model when you want to have a passkeys-first approach and not write it from scratch. I outlined the security limitations and trade-offs in the docs directory, and I encourage you to read through those.

That said, I used competing agents and industry best practices tm to try to find security issues and bugs outside my own reviews. It is still early in AI development efforts so judge those 'best practices' with a grain of salt given how nascent it is developing with AI tools.

I will be verifying this project by using it elsewhere in my work. The description of this git repository indicates if I feel it is production worthy or not. I will also try to get legitimate security folks to review it; but unless there is a note that they have reviewed the project, assume it is not.

The AI-as-supply-chain analysis lives in docs/threat-model.md → AI-authored code (provenance).]

About

passkey-centric drop-in authentication layer. AI built, experimental, not for production

Topics

Resources

Contributing

Security policy

Stars

2 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages