Passkeys are being used for additional authentication to access sensitive resources
such as AWS credentials and AWS consoles.
This doc describes the points of integration and where to find the most important code.
The serverside verification of passkeys is being done by the webauthn4j library. The documentation for that library is excellent and gives a good background to the integration.
graph TB
%% External components
subgraph Browser
JS["passkeys.js"]
end
Authenticator["Authenticator Device"]
DynamoPasskeys[(Passkeys table)]
DynamoChallenges[(PasskeyChallenges table)]
%% Main components
subgraph controllers
Controller["PasskeyController"]
end
subgraph filters
Filter["PasskeyAuthFilter"]
end
subgraph logic
Webauthn4J["Passkey"]
end
subgraph aws
PDB["PasskeyDB"]
PCDB["PasskeyChallengeDB"]
end
%% Relationships
Browser <--> Authenticator
JS --> Controller
Controller --> Filter
Controller --> Webauthn4J
Controller --> PDB
Controller --> PCDB
Filter --> Webauthn4J
Filter --> PDB
Filter --> PCDB
PDB --> DynamoPasskeys
PCDB --> DynamoChallenges
The device that generates a cryptographic key pair and stores the private key.
This could be a hardware device like a Yubikey or it could be software like Android password manager.
The user chooses this at registration time. We allow any authenticators that are available to the browser.
The web service or app that has an endpoint to protect. We would say that Janus is the RP in this scenario.
The integration is encapsulated in the following files:
Authentication takes place in the browser and the functions in this file control interactions between the server and the authenticator.
All the passkey-specific models passed between views and the database are defined here. Also model <-> Json marshalling rules.
This holds actions for registration of passkeys and for providing registration and authentication options to browsers at the beginning of registration and authentication flows respectively.
A filter for actions that are protected by passkey authentication.
A wrapper around the WebAuthn4j library methods to make them usable in controllers.
Controls all interactions with the Passkeys Dynamo DB table.
Controls all interactions with the PasskeyChallenges Dynamo DB table.
Two Dynamo tables are used to hold passkeys data.
Each item is a passkey public key and various pieces of metadata about the passkey. It's keyed by user ID and credential ID.
Each item is a transient challenge keyed by user ID. The TTL attribute gives the expiry time for the challenge. Once used, the challenges are removed from the table.
The browsers that have been tested all have slightly different behaviours with passkeys.
Chrome's default option is to use its own built-in passkey authenticator.
This is stored on the device where the browser is running so isn't synced across devices.
On a Mac, it will fall back to the iCloud Keychain authenticator if the user chooses.
Firefox uses the native OS mechanism to find a default authenticator which on a Mac is the iCloud Keychain. This means that without an Apple account there is no on-device authenticator for Firefox. Depending on how it's configured, an on-device password manager could be used instead.
Safari, as might be expected, uses the iCloud Keychain as its default authenticator. So behaviour is similar to Firefox.