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).
Last updated
Was this helpful?
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).
Last updated
Was this helpful?
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.
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.
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.
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:
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:
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
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:
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)
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.
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:
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.
The "Login with Handshake" - 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.