Skip to content

T7-Solution/Passkey-Spring-Boot-Demo

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Passkey Spring Boot Demo

This project demonstrates how to combine Spring Boot 3 + Spring Security 6 (session-based) with WebAuthn / Passkeys, Thymeleaf templates and a relational database (PostgreSQL or H2).


Table of contents

  1. Quick start
  2. Project structure
  3. Authentication flows (step-by-step)
  4. Configuration
  5. Postgres vs H2
  6. Extending WebAuthn logic

1 Quick start

# 1 - build & run
git clone <repo> passkey-demo && cd passkey-demo
./mvnw spring-boot:run

# 2 - open the app
open http://localhost:8080/register    # macOS (or just paste into a browser)

Default credentials: none – create a user first.


2 Project structure

src/main/java/com/example/passkey
├─ config/          Spring Security & other configurations
├─ controller/      MVC controllers (Auth, Dashboard, Passkey)
├─ model/           JPA entities (User, PasskeyCredential)
├─ repository/      Spring-Data repositories
├─ service/         Business logic (UserService, PasskeyService*)
└─ PasskeyApplication.java

src/main/resources
├─ templates/       Thymeleaf HTML pages
├─ application.properties
└─ static/          (css/js if needed)

PasskeyService still contains TODOs where the real WebAuthn server-side validation should be implemented (using webauthn-server-core).


3 Authentication flows

3.1 E-mail & password

  1. /register – user fills e-mail + password.
  2. UserService.register() hashes the password (BCrypt) and stores the User.
  3. /login – Spring Security form-login handles authentication, creates an HTTP session.
  4. /dashboard – secured page (requires ROLE_USER).

3.2 Register a passkey

  1. Logged-in user visits /passkey/register.
  2. Click Start Registration → JS calls /passkey/register/options to obtain a minimal PublicKeyCredentialCreationOptions JSON.
  3. Browser shows the passkey prompt (Touch ID / Windows Hello / etc.).
  4. Upon success, JS posts credentialId (+ stub fields) to /passkey/register/finish.
  5. PasskeyController.finishPasskeyRegistration() stores a PasskeyCredential entity and refreshes the security context so the dashboard immediately shows "You already have a registered passkey."

3.3 Sign-in with a passkey

  1. User opens /passkey/login and enters e-mail.
  2. JS fetches /passkey/login/options?email=… → server responds with PublicKeyCredentialRequestOptions containing the user's credential IDs.
  3. Browser shows the passkey prompt.
  4. On success JS posts credentialId + clientDataJson to /passkey/login/finish.
  5. Controller looks up the credential, creates a UsernamePasswordAuthenticationToken, saves it to the session, and redirects to /dashboard.

Note: server-side signature verification is stubbed – see TODO markers in PasskeyService for production-grade validation.


4 Configuration

Key Default Notes
spring.thymeleaf.cache false auto reload templates in dev
spring.jpa.hibernate.ddl-auto update auto-create / update schema
spring.jpa.show-sql true echo SQL in logs
CSRF enabled All forms include hidden CSRF token via Thymeleaf

5 PostgreSQL vs H2

The project runs on H2 by default. To switch to Postgres:

  1. Install Postgres locally (no Docker required).
  2. Create a database and user, e.g.
    psql -U postgres -c 'CREATE DATABASE passkey;'
  3. Edit application.propertiesuncomment the Postgres section and comment the H2 lines:
    spring.datasource.url=jdbc:postgresql://localhost:5432/passkey
    spring.datasource.username=postgres
    spring.datasource.password=postgres
    spring.datasource.driver-class-name=org.postgresql.Driver
    # spring.datasource.url=jdbc:h2:mem:testdb    # <- disabled
  4. Run the app – Hibernate will create the tables in Postgres.

Docker users can still run docker compose up -d db, but it's completely optional.


6 Extending WebAuthn logic (TODO)

  • Replace the stubbed methods in PasskeyService with real calls to RelyingParty.startRegistration, finishRegistration, startAssertion, finishAssertion from webauthn-server-core.
  • Transfer the full clientDataJSON, attestationObject, authenticatorData, signature etc. from the browser to the backend (currently only credentialId is sent for brevity).
  • Enforce origin / RP ID validation and signature counter tracking.
  • Use a migration tool (Flyway/Liquibase) for schema evolution instead of hibernate.ddl-auto.

Enjoy building with Passkeys 🚀

About

This project demonstrates how to combine **Spring Boot 3 + Spring Security 6** (session-based) with **WebAuthn / Passkeys**, Thymeleaf templates and a relational database (PostgreSQL or H2).

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors