Skip to content

Support refresh tokens #18

@tahpot

Description

@tahpot

The current auth flow is as follows:

  1. DID signs a consent message to unlock a context using the private key for the DID (this happens in the Vault).
  2. The signed consent message is sent to the storage node to perform all CRUD operations to manage their databases. This consent message is the "key" to unlock all database operation and never expires. This key is sent back to the web browser by the Vault, giving the web browser never-ending access. This needs to be fixed.
  3. The signed consent message is sent to the storage node to obtain a CouchDB auth token (with a fixed expiry) that is used to actually read / write from the DID's databases.

The key issue is at step (2).

We require the following capabilities:

  • As a Verida Vault I can sign a consent message using my private key to obtain a refresh token and access token to gain access to a storage node server for a given application context.
  • As a Verida Vault I can store the refresh token, linked to a given application context and Verida dApp so that I can track all the applications I have logged into
  • As a Verida dApp I can send a message to the Verida Vault and receive a refresh token and access token so that I can gain access to a storage node server for a given application context
  • As a Verida dApp I can use the access token to make requests to the storage node server so that I can manage databases
  • As a Verida dApp I can use the access token to make requests directly to CouchDB so that I can read / write database data
  • As a Verida dApp I can use the refresh token to obtain a new access token if it expires so that the user isn't logged out of the application
  • As a Verida dApp I can use the refresh token to obtain a new refresh token if it is getting close to expire so that the user isn't logged out of the application
  • As a Verida Vault I can revoke a refresh token, linked to a given application context and Verida dApp so that I can revoke database access to an application

The proposed new flow is as follows:

  1. DID signs a consent message to unlock a context using the private key for the DID (this happens in the Vault).
  2. The Vault sends the signed consent message to the storage node, which generates a storage node refresh token and access token via a new authenticate() endpoint
  3. The refresh token expires after (30?) days
  4. The Vault stores the refresh token in a app_connections database, linked to the application context and domain name that made the SSO request
  5. The Vault returns both tokens to the web browser.
  6. The web browser can use the access token make requests to the storage node or the couchdb server
  7. The web browser can use the refresh token to obtain a new access token / refresh token from the storage node server, if the access token / refresh token expires
  8. The Vault can revoke a refresh token granted to any Verida dApp at any time

Note: access tokens can't be revoked in couchdb, so we don't support revoking them at all. Instead they are short lived (5 minutes).

This requires the following updates to storage node:

  • generateAuthJwt(did:string, contextName: string) -- Begin the auth flow. Storage node generates a JWT containing a unique string that must be signed by the DID to complete authentication. Expires after 60 seconds.
  • authenticate(authJwt: string, did: string, contextName: string, signature: string, deviceId: string) -- Authenticate access to the storage node and couchdb server. Verifies a signature is signed for a given contextName and contains the unique string from a valid JWT. Returns a new refresh token and access token. Stores the refresh token on the server.
  • get(contextName: string, refreshToken: string) -- Update the existing get() method to accept a refresh token and return an access token with the database hostname.
  • invalidateDeviceId(deviceId: string) -- Invalidates all refresh tokens that have been generated for a given deviceId. This allows the Vault to sign out a particular device.
  • regenerateRefreshToken(refreshToken: string, contextName: string) -- Invalidates an existing refresh token and generates a new one. This enables an application to update the refresh token with a more recent expiry.
  • request validator middleware must be updated to validate all requests against a supplied access token.
  • Garbage collection of expired refresh tokens

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions