Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

fastify-opaque-apake

Package Overview
Dependencies
Maintainers
1
Versions
2
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

fastify-opaque-apake

Fastify plugin to implement the OPAQUE aPAKE protocol

  • 0.2.0
  • latest
  • Source
  • npm
  • Socket score

Version published
Weekly downloads
0
Maintainers
1
Weekly downloads
 
Created
Source

fastify-opaque-apake

License npm

Fastify plugin to implement the OPAQUE aPAKE protocol. Uses @squirrelchat/opaque-wasm-server under the hood, itself using opaque-ke to do the real work.

This plugins depends on @fastify/session (or any compatible plugin such as @fastify/secure-session) to handle state memoization during login. However, if you wish you can use it witout a session plugin.

The underlying library uses the following OPAQUE configuration, based on the recommendations of the OPAQUE draft:

  • OPRF: ristretto255-SHA512
  • KDF: HKDF-SHA-512
  • MAC: HMAC-SHA-512
  • Hash: SHA-512
  • Group: ristretto255

Make sure to match this configuration in your clients, otherwise the protocol will not be able to execute. For browser clients, we recommend @squirrelchat/opaque-wasm-client. Totally unbiased recommendation, of course :whistle:

Installation

[pnpm | yarn | npm] i fastify-opaque-apake

Usage

fastify.register(import('@fastify/cookie'), { ... })
fastify.register(import('@fastify/session'), { ... })
fastify.register(import('fastify-opaque-apake'), { ... })

Once registered, you have the OPAQUE server instance accessible via fastify.opaque. However, you shouldn't need to use it as more convenient methods are added to the FastifyRequest object.

These methods will handle temporary state holding for you (by forwarding the work to @fastify/session, itself capable of dealing with scaled environments by using a Redis-backed store for example).

The examples below are absolutely NOT production ready. They show off the API of the plugin, but lack error handling. Every call to *Opaque* should be wrapped in a try/catch block, body should be validated (at least make sure it's an array of numbers, the rest will be handled by the lib)!

fastify.post('/auth/register/init', (request, reply) => {
	const reqBytes = new Uint8Array(request.body.request)
	const resBytes = request.startOpaqueRegistration(request.body.username, reqBytes)
	return { response: Array.from(resBytes) }
})

fastify.post('/auth/register/finalize', (request, reply) => {
	const recordBytes = new Uint8Array(request.body.record)
	const credentials = request.finishOpaqueRegistration()
	// store credentials to database

	reply.code(204).send()
})

fastify.post('/auth/login/init', (request, reply) => {
	// fetch record from database
	const record = ...

	// A note on account enumeration:
	// The OPAQUE protocol protects against account enumeration
	// by design during authentication. To achieve this, you must
	// engage in the protocol even if the account does not exists.
	// opaque-wasm and the underlying lib does this by using a fake
	// random record when no record is specified.
	//
	// Whether to do this step or not is up to you. If account
	// enumeration during authentication is not a concern for you,
	// you may skip this and simply send a clear error right now to
	// the client.
	const reqBytes = new Uint8Array(request.body.request)
	const resBytes = request.startOpaqueLogin(request.body.username, reqBytes, record)
	return { response: Array.from(resBytes) }
})

fastify.post('/auth/login/finalize', (request, reply) => {
	const finishBytes = new Uint8Array(request.body.finish)
	const sessionKey = request.finishOpaqueLogin(finishBytes)
	reply.code(204).send()
})

Configuring state

The state holds the salt and the keypair used by the server. This keypair must not change, and must be the same across all instances if you have multiple instances of your app. There are 3 ways of providing the state to the plugin: using a static one, using a provider, or pointing to a file.

With a static state, you are responsible for loading/saving the state.

const state = loadState()

fastify.register(import('fastify-opaque-apake'), { state: state })
	.after()
	.then(() => saveState(fastify.opaque.getState()))

With a provider, the library uses functions you've provided to load/save the state. Your functions can return promises and the library will await them accordingly.

fastify.register(import('fastify-opaque-apake'), {
	getState: () => ...,
	setState: (state) => { ... },
})

When pointing to a file, the plugin will read/write the file by itself. Please note that the OPAQUE keys are extremely sensitive, and storing them to a file isn't the best for security.

fastify.register(import('fastify-opaque-apake'), { stateFile: './opaque.bin' })

Usage without a session plugin

In case you need to handle the OPAQUE state in a specific way, and don't want to register a session plugin for this reason, you can use fastify-opaque-apake/core.

fastify.register(import('fastify-opaque-apake/core'), { ... })

When registered like this, you only get the fastify.opaque decorator. The helpers on FastifyRequest are not registered, and you must handle the state management by yourself during login.

FAQs

Package last updated on 27 Apr 2023

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc