Handshake Login Implementation Guide
Use this resource if you're looking to create your own implementation of Handshake login (or explore how we implemented Handshake login in services like Namer News).
OIDC Implementations Using Handshake
Rather than asking a user to provide a password for a specified username as is typical in a standard OIDC implementation, when authenticating using Handshake the authorization server asks the user to sign a challenge using the private key corresponding to the public key that is pinned to their specified Handshake name.
In the Handshake case, there is no centralized authority that performs this signature verification. In a traditional implementation, if Github provided the authorization server, they would be the only authority able to validate Github usernames and passwords.
However, anybody can:
run a Handshake full node
query a Handshake name for its pinned public key
validate that a challenge was signed by the correct public key
If a blog wants to add support for logging in with Handshake, then that blog can run their own OIDC authorization server that implements the protocol specified in this document. There's no need to trust any centralized parties for authentication. The blog only needs to trust Handshake.
With this being said, for convenience, that blog could use a third-party Handshake authorization server, provided they trust the organization running it. Namebase runs an authorization server for Namer News, and developers that are interested in using it in their applications can use it once it is open to the public.
Alternatively, developers can host their own authorization server.
Now let's go through how the specific Namer News login implementation works in detail. We hope this can act as a guide for others to implement their own authorization flows.
Here is an open source OIDC Authentication Server: https://github.com/namebasehq/handshake-oidc
Overview
When implementing OIDC with Handshake, the OIDC provider makes a Handshake DNS query to fetch a TXT record which contains a fingerprint of the user's public key. The user's ability to sign a challenge with their private key is what proves their identity to Handshake, the OIDC provider, and the application requesting identity.
To minimize trust, we recommend each application host their own OIDC provider to handle queries to the Handshake network as opposed to relying on a third-party provider.
"Login with Handshake" Identity Manager
The "Login with Handshake" Identity Manager - in this example implementation - manages the identities of the user's keys linked to their respective Handshake domains. This is so that the associated keys are securely accessible when implementing the Login with Handshake flow.
In this example implementation, we are showing one example of how keys can be handled. The specifics of how you manage the keys, via the Identity Manager or otherwise, is up to the discretion of each developer. This could be via a hardware wallet, using WebAuthn, or any custom key management solution.
In this case, the extension stores a public and private key pair for each domain a user has associated with their domain records. Everything is stored locally, and the keys stored are unique from their ownership public and private keys. This means that even if the data stored in a user's extension was compromised, user's domains themselves would still be entirely safe.
Walkthrough
1. OIDC client discovers the authority public keys
Before users ever interact with your platform, the OIDC client will discover the authority public keys from the OIDC provider.
To configure the OIDC client:
2. Replay attack defense
When a user tries to access secured content, the OIDC client generates replay attack defense and redirects the user to the OIDC provider.
Let's cache the code_verifier to verify the response at the end of the login flow and let's generate the authorization URL:
3. The OIDC provider fetch the TXT record on the subdmain _idmanager and redirect to the identity manager passing the relevant encoded data as a hash query
Locate the associated identity manager:
Let's redirect to the id manager:
state is used to prevent replay attack
id identifies who is trying to log in
callbackUrl specifies the oidc endpoint where the data need to be posted back
4. User creates their new identity
If users are simply selecting a domain that they have already used to set up a profile, skip to Step 5.
The user is then prompted to create a new identity by providing the name of an owned handshake domain or subdomain.
The identity manager generates a new pair of asymmetric keys. The fingerprint of the public key is stored on a dedicated TXT records and should returns the following format:
The prefix is generated by concatenating a randomly generated device identifier and the name, then hashing with SHA-256 and keeping only the first 16 characters:
5. Identity selection, and the OIDC provider page
The user selects an identity from the list displayed via the identity manager which injects into the OIDC provider page:
the random string {no replay} is signed with the identity private key.
the original random string. {no replay}
the public key of the selected identity.
the handshake domain used as identity.
the device prefix generated for the name: hash(deviceId+name)
6. TXT record fetch, and hash finding
At this stage, the OIDC provider fetches the TXT Records of the _auth. subdomain from the supplied handshake domain name and tries to find the hash.
It then extracts the value from the TXT records.
dnsResolvers provides a list of IPs of servers resolving handshake names
7. Fingerprint comparison, and replay attack verification
At this stage, the OIDC provider compares the fingerprint on the DNS records with the fingerprint of the supplied public key. The signed string is compared, and verified with the public key. The {no-replay} value is verified.
In our implementation, the fingerprint on the TXT record is fetched using HDNS:
Then we verify that the fingerprint matches:
And we verify that the challenge has been signed by the correct key:
8. Provider generates claims, user is authenticated
Finally, the OIDC provider generates the required claims and signs a JWT token. This is returned to the client where the user is now authenticated.
Last updated