Express DID Auth - a challenge-response authentication model based in DIDs

This package is an implementation of the DID Auth protocol. It is designed to be easely integrated to any Express application.

Main features:

Usage

Install

npm i @rsksmart/express-did-auth

Plug and play

This is the simplest approach. Just need to provide an express app and the desired configuration for the package and it will create the needed endpoints on your behalf.

import express from 'express'
import setupApp, { ExpressDidAuthConfig } from '@rsksmart/express-did-auth'

const config: ExpressDidAuthConfig = {
  // your config
}

const app = express()

const authMiddleware = setupApp(config)(app)

app.get('/not-protected', function (req, res) {
  res.send('This endpoint is not authenticating')
})

app.get('/protected', authMiddleware, function (req, res) {
  res.send('This endpoint is authenticating')
})

const port = process.env.PORT || 5000

app.listen(port, () => logger.info(`My express API with did-auth running in ${port}`))

Configure

All the configuration should be placed in just one object of type ExpressDidAuthConfig. That object may contain the following fields:

REQUIRED

challengeSecret: string: the secret that will be used to generate the deterministic challenge. See how we create deterministic challenges

serviceUrl: string: will be used as the audience of all the JWTs expected or emitted by this package. Should be a URI that identifies your service in the context where it is run

serviceDid: string: the did controlled by the servie. Will be used to sign JWTs.

serviceSigner: Signer: the signing function associated to the serviceDid. MUST implement ES256K algorithm, please find an example here

OPTIONAL

useCookies: boolean: determines if the access token and refresh token are saved in cookies or are returned in the body of the response. If true, the tokens will be extracted from the cookies. See how to send tokens for more information. Default: false

requestSignupPath: string: the request signup endpoint route. Default: /request-signup

signupPath: string: the signup endpoint route. Default: /signup

requestAuthPath: string: the request auth endpoint route. Default: /request-auth

authPath: string: the auth endpoint route. Default: /auth

logoutPath: string: the logout endpoint route. Default: /logout

refreshTokenPath: string: the refresh token endpoint route. Default: /refresh-token

challengeExpirationTimeInSeconds: number: the max expiration time for the generated challenge when requesting signup or auth. MUST be provided in seconds. Default: 300 (5 minutes)

maxRequestsPerTimeSlot: number: the max amount of requests per did per timeslot. Default: 20

timeSlotInSeconds: number: the amount of seconds that need to elapse before resetting the request counter. Default: 600 (10 minutes)

userSessionDurationInHours: number: the validity of each refresh token in hours. Default: 168 (one week)

rpcUrl: string: rpc url used to resolve Ethr DID identities. If not provided, will resolve using both RSK Mainnet and Testnet networks.

networkName: string: network name used to resolve Ethr DID identities. If not provided, will resolve using both RSK Mainnet and Testnet networks.

registry: string: DID Registry address used to resolve Ethr DID identities. Default: 0xdca7ef03e98e0dc2b855be647c39abe984fcf21b

accessTokenExpirationTimeInSeconds: number: the validity in seconds of each access token. Remember that it should be short because the long validity is for the refresh token. Default: 600 (10 minutes)

authenticationBusinessLogic: AuthenticationBusinessLogic: the business logic to execute when a DID tries to log in. Will be executed each time the /auth endpoint is invoked with a valid signature. If it throws an error, the error message will be returned as part of an HTTP 401 response. If not present, no business logic will be executed.

requiredCredentials: string[]: array of Verifiable Credential schemas that will be requested as part of the signup process. If neither requiredCredentials and requiredClaims are present, no sdr will be requested when a user signs up.

requiredClaims: Claim[]: array of Claims that will be requested as part of the signup process. If neither requiredCredentials and requiredClaims are present, no sdr will be requested when a user signs up.

signupBusinessLogic: SignupBusinessLogic: the business logic to execute when a DID tries to sign up. It receives the required sdr as part of the payload. Will be executed each time the /signup endpoint is invoked with a valid signature. If it throws an error, the error message will be returned as part of an HTTP 401 response. Should be used to validate the sdr against the business needings and/or to save users in any storage for future authentication validation. If not present, no business logic will be executed.

Included artifacts

Endpoints

GET /request-signup/:did

Expects the user did in the params of the request. Returns an HTTP 200 with a JSON containing { challenge, sdr? } in the body of the response. The sdr will be present if the service requires it to register the user. See more information in the protocol.

Possible error messages:

POST /signup

Expects the signed challenge and sdr (if needed) response in the body of the request as { response }. If using cookies, sets the cookies in the service and returns just an HTTP 200 with no content. If not using cookies, returns an HTTP 200 with a JSON containing { accessToken, refreshToken }.

Possible error messages (all HTTP 401):

GET /request-auth/:did: { challenge }

Expects the user did in the params of the requests. Returns an HTTP 200 with a JSON containing { challenge } in the body of the response.

Possible error messages:

POST /auth

Expects the signed challenge response in the body of the request as { response }. If using cookies, sets the cookies in the service and returns just an HTTP 200 with no content to the client. If not using cookies, returns an HTTP 200 with a JSON containing { accessToken, refreshToken }.

Possible error messages (all HTTP 401):

POST /refresh-token

If using cookies, will get the refresh token from a cookie. If not, expects the refresh token in the body of the request as { refreshToken }. Validates user session and:

Possible error messages (all HTTP 401):

POST /logout

This is a protected endpoint, so the auth middleware is executed before.

It invalidates the current user session and returns an HTTP 200 with no content.

It has not own validations, so the error messages it may respond with comes from the middleware.

Auth Middleware

Authenticates requests by checking the access token. If using cookies, will get it from a cookie. If not, expects the access token in the Authorization header of the request with the DID Auth scheme (DIDAuth ${accessToken}). It validates the extracted token and if it fullfils the protocol needs, it authenticates the request by injecting the user did in the request object so it is available to be used by the endpoint. The did will be injected under req.user.

Possible error messages (all HTTP 401):

Run for development

The service source code is hosted in Github, so please refer directly to the README and check there the detailed guide to install and test the service locally.