Login with hyperware
Hyperware provides a secure PKI hosted in the Base network. Every hyperware node has a keypair which can be used to identify itself or sign messages.
For apps distributed inside hyperware, users are logged in by default, as the node reads the user identity from the hyperware node itself.
This package provides a library and example clients for using a Hyperware identity to login to applications and servers running outside hyperware.
There are three ways of using your Hyperware ID to authenticate to external applications:
- Node-initiated
- Server-initiated OTP
- TOTP
Node-initiated authentication
This method is suited for hybrid apps which have a pubilc facing frontend but also want to exclusive features to Hyperware users. The setup requires two parts:
- A hyperware package with a login frontend loaded inside hyperware ("the Client")
- Handling logic on the server ("the Server").
The basic idea is that users will login to your server using the hyperware package. Your server will issue an authentication token (not a cookie, as browser cookies are associated with the request origin, so here the cookie is already used for the browser to login to the user's hyperware web UI). The hyperware package will store the authentication token in the main process state. When a user accesses the package frontend, it will first check for the existence of an authentication token. If none exists, it will serve a login page. If it does, it will request your public facing frontend adding the auth token as a header in every request.
Server-side (Your public facing server)
You can see an example server as a barebones NextJS application in the nextclient
folder.
- Import the
hyperware-login
JavaScript library (thelib
folder in this repo) to your app. - Set an endpoint in your server expecting an HTTP
POST
request with the following body:
{
"node": <the user's node id name>,
"message": <the message that was signed as an array of numbers>,
"signature": <the signature as an array of numbers>
}
- Instantiate a Kimap client by running:
import "KimapClient" from "hyperware-login"
const kimap = new KimapClient(process.env.BASESCAN_API_KEY!);
- Verify the signature sent to the endpoint by running:
const verificationResponse = await kimap.verifySignature(
node,
message,
signature,
);
The kimap.verifySignature()
method will return a Promise<{ok: boolean} | {error: string}>
If the verification is successful, generate an authentication token of your choice as a string.
5. Send a response to the request. In the example, if the verification is successful, the NextJS endpoint returns {ok: true}
, and an HTTP header x-hyperware-auth
with the authentication token if the verification was successful. If the verification was unsuccessful the server returns {error: string}
with different error messages, depending if the signature verification failed or there was any other error in the process.
6. Handle users accessing your public frontend from within hyperware. In the example, requests from hyperware have an HTTP header hypr-auth
with the authentication token issued by your server.
Client-side (Hyperware package)
You can see a barebones example in the client
folder. You can load it by cloning the repo and running kit bs
inside the client
folder.
-
Make a hyperware package with a UI.
-
The package backend should expect requests, to three kinds of paths: the login frontend, the login API endpoint, and anything else, which will be redirected to your server. In the example, these are respectively
GET /hypr-login
,POST /hypr-login
and else. -
Make a simple login interface in HTML (as in
client/pkg/ui/index.html
) and have the package serve that UI from a non root path. In the provided example the path is/hypr-login
. -
The frontend should have a button that triggers an ajax
POST
request to the package backend in a non root path. In the example (seeclient/pkg/ui/script.js
) we send the request to<package_path>/hypr-login
. -
The request body should be a json object with the following shape:
{
"Sign": null
}
- Handle that request in the package backend (
client/loginex/src/lib.rs
in the example):- You can see an example handling the login request in the
handle_login_request()
function. The login request will do the following:- Generate a signature with the user's hyperware identity's keypair.
- Send an HTTP
POST
request to the public facing server with the following json body:
{ "node": <the user's node id name>, "message": <the message that was signed as an array of numbers>, "signature": <the signature as an array of numbers> }
- Await the response from the server.
- If the response is positive, grab the authentication token from the response. In the provided example the token is in the
x-hyperware-auth
header of the response. Save the authentication token to the process state. - Send the result back to the hyperware frontend as a json object of the following shape:
You are encouraged to handle the errors in your frontend to inform the user of the problem or however you see fit. If the response is successful, redirect the frontend to the root path of the package. Now that an authentication token has been set, this will request and render your public frontend.{ok: boolean} | {error: string}
- You can see an example handling the login request in the