DEV Community

Mitchell Cuevas for Blockstack

Posted on • Originally published at blog.blockstack.org on

Blockstack authentication server-side  — node.js

This post was originally published on Medium.com by George Bennet and is republished with permission.

The Blockstack authentication flow enables users to authenticate themselves in an entirely client-side fashion. This way, users can port their identity and private data without the need for third party authentication.

But… what if you need to authenticate with a server? Users may need to authenticate with third parties in order to access services that they trust. Luckily, Blockstack has all the methods required to support this use case.

Client set-up

The first half of the flow works exactly the same as the client-only flow described in the Blockstack guide. Your app will generate an authRequest with the necessary scopes and redirect your user to the blockstack browser. Your user will return to the callback URL with an authResponse JWT which contains all the information needed to authenticate the user. You’ll need to POST the authResponse to your server for authentication.

Server set-up

The authResponse token contains all the information needed to authenticate your user including a unique identifier, email address and the URL needed to fetch the user’s profile data.

  • First, we can use the blockstack.verifyAuthResponse() method to verify that the authResponse is valid
  • Then, decode the JWT to reveal the user’s unique identifier, email and profile URL
  • Then, perform a GET request to the profile URL to retrieve the user’s name
\*\* FOR DEMONSTRATION PURPOSES ONLY \*\*

import request from "request-promise" import { verifyAuthResponse } from "blockstack" import { decodeToken } from "jsontokens"

async function blockstackAuth(req: Request, res: Response) { const LOOKUP\_URL = "https://core.blockstack.org/v1/names" const authResponse = req.body.authResponse let token: any try { const valid = await verifyAuthResponse(authResponse, LOOKUP\_URL) token = decodeToken(authResponse).payload if (!valid || !token) { throw new Error("invalid authResponse.") } } catch (e) { return res.status(400).send(e) } const userJSON = await request(token.profile\_url) const userToken = JSON.parse(userProfile)[0].decodedToken const userData = userToken.payload.claim const userUniqueIdentifier = token.iss const userEmail = token.email const userFullName = userData.name // Some logic relating to the now authenticated user e.g. sign-up

res.status(200).send({ message: "all good!" }) }

*Catch — clock skew *

Time sensitive JWT authentication can suffer from clock skew, whereby the issuer’s time and the authenticator’s time is out of sync.

If you find that a blockstack authResponse is deemed invalid by your server, it might be because your server’s time is behind that of the server which issued the authResponse. ** The **blockstack.verifyAuthResponse() method will deem the ** ** futuristic issuance time as invalid.

To resolve this, at Zinc, we omitted the issuance validation of the blockstack.verifyAuthResponse() *method * ** in favour of a custom method which allowed for time discrepancy (or “leeway” by the JWT standard). We made use of the Blockstack component functions to re-construct our own **authResponse validation:

// blockstack.js methods await blockstack.isExpirationDateValid(authResponse) await blockstack.doSignaturesMatchPublicKeys(authResponse) await blockstack.doPublicKeysMatchIssuer(authResponse) await blockstack.doPublicKeysMatchUsername(authResponse, LOOKUP\_URL)

// custom issuance date validation method await isIssuanceDateValid(authResponse, {leeway: 30})

The post Blockstack authentication server-side  — node.js appeared first on Blockstack Blog - Blockstack.

Top comments (0)