A companion project for the Tucanoo tutorial article on adding passkeys (WebAuthn) to a Grails application.
This repository demonstrates a practical migration path:
- Existing Grails CRM app
- Spring Security login
- Add passkey enrollment and passkey sign-in
- Prompt users after password login to create their first passkey
This project builds on the original Tucanoo Grails CRM tutorial but now uses Grails 7:
- Repository: https://github.com/tucanoo/crm_grails
- Article: https://tucanoo.com/how-to-build-a-simple-crm-with-grails-4/
- Java 25+ (
java -version)
No separate Gradle installation is required. The Gradle wrapper is included.
git clone https://github.com/tucanoo/crm_grails.git
cd crm_grails
./gradlew bootRunWindows PowerShell:
git clone https://github.com/tucanoo/crm_grails.git
cd crm_grails
.\gradlew.bat bootRunOpen http://localhost:8080 and sign in with:
- Username:
user - Password:
changeme
- Sign in with username/password.
- You are redirected to
/dashboard/index. - If no passkeys exist for your account, a banner appears.
- Click
Create passkeyand complete browser/device verification. - Log out.
- On the login page, click
Sign in with passkey.
| Feature | Where to look |
|---|---|
| Password login with in-memory user | src/main/groovy/com/tucanoo/security/InMemoryUserDetailsService.groovy |
Passkey registration API (registerOptions, registerComplete) |
grails-app/controllers/com/tucanoo/security/passkey/PasskeyController.groovy |
Passkey authentication API (authOptions, authComplete) |
grails-app/controllers/com/tucanoo/security/passkey/PasskeyController.groovy |
| WebAuthn server orchestration | grails-app/services/com/tucanoo/security/passkey/PasskeyService.groovy |
| WebAuthn credential repository adapter | src/main/groovy/com/tucanoo/security/passkey/PasskeyCredentialRepository.groovy |
| One-time challenge cache | src/main/groovy/com/tucanoo/security/passkey/PasskeyChallengeCache.groovy |
| RelyingParty bean configuration | src/main/groovy/com/tucanoo/security/passkey/PasskeyConfiguration.groovy and grails-app/conf/spring/resources.groovy |
| Login page passkey button and browser WebAuthn JS | grails-app/views/login/auth.gsp |
| Post-login passkey setup banner | grails-app/controllers/com/tucanoo/DashboardController.groovy and grails-app/views/dashboard/index.gsp |
| Persisted passkey credentials | grails-app/domain/com/tucanoo/security/PasskeyCredential.groovy |
Main settings live in grails-app/conf/application.yml.
app:
security:
username: user
password: changeme
role: CRM_USERpasskeys:
enabled: true
rpId: localhost
rpName: Simple CRM
origins:
- http://localhost:8080
- http://127.0.0.1:8080
attestation: none
allowUsernameless: false
challengeTtlSeconds: 300
maxCredentialsPerUser: 5Notes:
rpIdandoriginsmust match where your app is served.- Localhost is allowed as a secure context for WebAuthn in modern browsers.
- If you deploy to another host/domain, update both
rpIdandorigins.
- Grails 7.0.7
- Spring Security Core plugin (
org.apache.grails:grails-spring-security:7.0.0) - Yubico WebAuthn server (
com.yubico:webauthn-server-core:2.8.1) - GSP + asset-pipeline
- H2 database
grails-app/
conf/
application.yml
spring/resources.groovy
controllers/com/tucanoo/
DashboardController.groovy
crm/CustomerController.groovy
security/passkey/PasskeyController.groovy
domain/com/tucanoo/
crm/Customer.groovy
security/PasskeyCredential.groovy
services/com/tucanoo/
crm/CustomerService.groovy
security/passkey/PasskeyService.groovy
views/
login/auth.gsp
dashboard/index.gsp
customer/*.gsp
src/main/groovy/com/tucanoo/security/
InMemoryUserDetailsService.groovy
passkey/
PasskeyConfiguration.groovy
PasskeyCredentialRepository.groovy
PasskeyChallengeCache.groovy
./gradlew test integrationTestWindows PowerShell:
.\gradlew.bat test integrationTestPasskeys disabled: setpasskeys.enabled: true.Origin not allowed: add your exact scheme/host/port topasskeys.origins.- Browser says passkeys unsupported: test on a current browser with WebAuthn support.
- No banner after login: confirm user has no rows in
passkey_credentialwithrevoked = false.
- Grails docs: https://grails.apache.org/docs/7.0.7/guide/index.html
- Yubico java-webauthn-server: https://github.com/Yubico/java-webauthn-server