Add WebAuthn / passkey client + Auth0 / Firebase passkey helpers#5039
Merged
Conversation
Extends the OidcClient identity stack (#5018) with a portable WebAuthn client. Most CN1 apps that sign users in via OidcClient already get passkeys for free (the IdP handles the ceremony, OIDC just delivers the tokens) -- this lands the surface for apps that talk to their own relying-party backend, or that want to drive Auth0 / Firebase passkeys directly. * New com.codename1.io.webauthn package: WebAuthnClient (create/get with the W3C JSON wire format), WebAuthnNative SPI, PublicKeyCredentialCreationOptions / RequestOptions / response wrapper with verbatim toJson() round-trip, WebAuthnException with W3C-named codes (NotAllowedError, InvalidStateError, SecurityError, etc.). * iOS port: ASAuthorizationPlatformPublicKeyCredentialProvider impl (iOS 16+) in Ports/iOSPort/nativeSources/CN1WebAuthn.m. Gated behind the existing CN1_INCLUDE_WEBAUTHN define so apps that never use passkeys ship without the symbols. AuthenticationServices.framework was already auto-linked by the OIDC scanner branch; IPhoneBuilder now also flips the CN1_INCLUDE_WEBAUTHN define when the classpath scanner sees com.codename1.io.webauthn.* references. * Android port: androidx.credentials.CredentialManager impl via reflection (so the port itself doesn't need androidx.credentials on its compile classpath). AndroidGradleBuilder auto-injects androidx.credentials:credentials + credentials-play-services-auth when the app references the WebAuthn classes; versions can be overridden via android.credentialsVersion build hint. * Provider passkey helpers: Auth0Connect.signInWithPasskey / registerPasskey (Auth0 WebAuthn grant_type), FirebaseAuth. signInWithPasskey / registerPasskey (Identity Platform v2 passkey REST endpoints). Both drive WebAuthnClient under the hood and return tokens through the existing OidcTokens / FirebaseUser model. * Tests: 14 new WebAuthnCoreTest assertions (options parsing, response parsing, builder round-trip, exception code mapping, async dispatch with a stub provider). Async tests use a CountDownLatch wired through .ready/.except instead of AsyncResource.get(timeout) to avoid the missed-notify race in the observer/wait path when the worker thread races against the registration. * Docs: new "Passkeys / WebAuthn" section in the Authentication and Identity chapter covering when to use the API, platform requirements (Associated Domains on iOS 16+, Digital Asset Links on Android API 28+), the Auth0 and Firebase passkey recipes, and the W3C error-code mapping. * CI: extended .github/workflows/identity-stack.yml path filters, unit-test list, Android bundle verification, and clang -fsyntax-only step to cover the new WebAuthn sources. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Contributor
|
Developer Guide build artifacts are available for download from this workflow run:
Developer Guide quality checks: |
Collaborator
Author
|
Compared 20 screenshots: 20 matched. |
Contributor
Cloudflare Preview
|
The WebAuthn stack ships in the same 7.0.245 release as the OidcClient identity stack (#5018); the original 7.0.246 tag was off by one. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Collaborator
Author
|
Compared 110 screenshots: 110 matched. Native Android coverage
✅ Native Android screenshot tests passed. Native Android coverage
Benchmark ResultsDetailed Performance Metrics
|
Collaborator
Author
|
Compared 110 screenshots: 110 matched. Benchmark Results
Build and Run Timing
Detailed Performance Metrics
|
Collaborator
Author
|
Compared 110 screenshots: 110 matched. Benchmark Results
Build and Run Timing
Detailed Performance Metrics
|
The first CI run on PR #5039 turned up three categorized issues, all contained to the new WebAuthn / passkey surface. * SpotBugs SIC_INNER_SHOULD_BE_STATIC_ANON (5×) in FirebaseAuth's passkey helpers. The flagged anonymous SuccessCallback / ConnectionRequest bodies only referenced captured locals plus static utilities, so SpotBugs flagged them as candidates for promotion to named static nested classes. Refactored each body into a private instance method (`onPasskeyEnrollmentStart`, `onPasskeySignInStart`, `completeFromMap`, `handlePostJsonRawResponse`) that the callback delegates to. This matches the existing FirebaseAuth#enqueue pattern, which also uses an anonymous ConnectionRequest body that pins the enclosing instance via a `persist(u)` call. Added an `ErrorForwarder` named static class for the repeated `.except(throwable -> out.error(throwable))` boilerplate so the call sites stay readable. * Vale (8×) in the new Passkeys / WebAuthn section. Replaced the "for free" cliche; de-hyphenated "auto-linked" / "auto-injected" per Microsoft.Auto style; switched four "does not" / "could not" to contractions. * LanguageTool (11×). Added `IdP`, `webauthn`, `[Pp]asskey(s)?` to the developer-guide accept list (technical terminology). Replaced the seven `->` HTML-entity arrows in the Auth0 / Firebase console navigation paths with the Unicode `→` (`→`) the rule suggests. Fixed the British "enrol" / "enrols" spellings to the American "enroll" / "enrolls" the dictionary prefers. 44/44 identity-stack tests still pass and `vale` reports zero issues on the chapter locally. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Second CI pass on PR #5039 turned up PMD warnings that the project treats as build-breaking: * MissingOverride on the two `run()` methods in WebAuthnClient's CreateRunnable / GetRunnable named static classes -- both implement Runnable.run() and were missing the annotation. * ControlStatementBraces (7×) on single-line `if (cond) stmt;` shapes in the JSON-building helpers I added to Auth0Connect (separator emission in joinScopes, mapToJson, mapToFlatJson, appendValue) and FirebaseAuth (serialiseMap, appendValue). Expanded each to the braced form. All 44 identity-stack tests still pass. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Contributor
✅ Continuous Quality ReportTest & Coverage
Static Analysis
Generated automatically by the PR CI workflow. |
shai-almog
added a commit
that referenced
this pull request
May 25, 2026
Combine the two non-overlapping accept-list blocks (router & JS port identifiers from this PR, WebAuthn / passkey terms from master's #5039) into one section.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Extends the OidcClient identity stack (#5018) with a portable WebAuthn / passkey client and provider passkey helpers.
com.codename1.io.webauthnpackage:WebAuthnClient(W3C JSON wire format),WebAuthnNativeSPI, options + response wrappers (PublicKeyCredentialCreationOptions,PublicKeyCredentialRequestOptions,PublicKeyCredential),WebAuthnExceptionwith W3C-named codesASAuthorizationPlatformPublicKeyCredentialProvideron iOS 16+,androidx.credentials.CredentialManageron Android API 28+Auth0Connect.signInWithPasskey/.registerPasskey(Auth0 WebAuthn grant),FirebaseAuth.signInWithPasskey/.registerPasskey(Identity Platform v2 REST endpoints)WebAuthnCoreTestassertions; the 30 existing identity-stack tests still passWhy now
Most CN1 apps that sign users in via
OidcClientagainst Google / Apple / Microsoft / Auth0 / Firebase already get passkeys transparently -- the IdP handles the ceremony, OIDC just hands you the resulting tokens. This PR lands the surface for the cases that don't have that path:Architecture
Mirrors the OIDC stack:
coreis platform-neutral; the actual passkey call goes through aWebAuthnNativeSPIWebAuthnClient.setProvider(...)from a generated init stubIPhoneBuilder/AndroidGradleBuilderonly flip the bridge on when the classpath scanner seescom.codename1.io.webauthn.*references, so apps that never use passkeys ship without the symbols or extra Gradle depswebauthn4j,@simplewebauthn/server,webauthn-rs, etc.)Test plan
WebAuthnCoreTest(14 assertions) -- pure-JVM coverage of options / response parsing, builder round-trip, exception codes, async dispatch with a stub providerOidcCoreTest,WebAuthnCoreTest,Oauth2Test,Oauth2RefreshTokenRequestTest,GoogleConnectTest,FacebookConnectTest,LoginTest,Login1Test,LoginExtrasTestall passIPhoneBuilder+AndroidGradleBuilderscanner changes)WebAuthnNativeImpl.javaships inandroid_port_sources.jar)clang -fsyntax-onlyonCN1WebAuthn.magainst the iPhoneOS SDK in bothstubsandfullconfigurationsassetlinks.jsonpublished (manual)🤖 Generated with Claude Code