Giter Club home page Giter Club logo

fastify-secure-session's Introduction

@fastify/secure-session

CI NPM version js-standard-style

Create a secure stateless cookie session for Fastify, based on libsodium's Secret Key Box Encryption and @fastify/cookie.

Using a pregenerated key

First generate a key with:

npx @fastify/secure-session > secret-key

If running in Windows Powershell, you should use this command instead:

npx @fastify/secure-session | Out-File -Encoding default -NoNewline -FilePath secret-key

If you have not previously used this module with npx, you will be prompted to install it, which with the output redirect will cause the command to wait forever for input.

To avoid this use the --yes flag with npx:

npx --yes @fastify/secure-session > secret-key

If you don't want to use npx, you can still generate the secret-key installing the @fastify/secure-session library with your choice package manager, and then:

./node_modules/@fastify/secure-session/genkey.js > secret-key

Then, register the plugin as follows:

'use strict'

const fastify = require('fastify')({ logger: false })
const fs = require('node:fs')
const path = require('node:path')

fastify.register(require('@fastify/secure-session'), {
  // the name of the attribute decorated on the request-object, defaults to 'session'
  sessionName: 'session',
  // the name of the session cookie, defaults to value of sessionName
  cookieName: 'my-session-cookie',
  // adapt this to point to the directory where secret-key is located
  key: fs.readFileSync(path.join(__dirname, 'secret-key')),
  // the amount of time the session is considered valid; this is different from the cookie options
  // and based on value wihin the session.
  expiry: 24 * 60 * 60, // Default 1 day
  cookie: {
    path: '/'
    // options for setCookie, see https://github.com/fastify/fastify-cookie
  }
})

fastify.post('/', (request, reply) => {
  request.session.set('data', request.body)

  // or when using a custom sessionName: 
  request.customSessionName.set('data', request.body)

  reply.send('hello world')
})

fastify.get('/', (request, reply) => {
  const data = request.session.get('data')
  if (!data) {
    reply.code(404).send()
    return
  }
  reply.send(data)
})

fastify.get('/ping', (request, reply) => {
  request.session.options({maxAge: 3600})
  
  // Send the session cookie to the client even if the session data didn't change
  // can be used to update cookie expiration
  request.session.touch()
  reply.send('pong')
})

fastify.post('/logout', (request, reply) => {
  request.session.delete()
  reply.send('logged out')
})

If you enable debug level logging, you will see what steps the library is doing and understand why a session you expect to be there is not present. For extra details, you can also enable trace level logging.

Note: Instead of using the get and set methods as seen above, you may also wish to use property getters and setters to make your code compatible with other libraries ie request.session.data = request.body and const data = request.session.data are also possible. However, if you want to have properties named changed or deleted in your session data, they can only be accessed via session.get() and session.set(). (Those are the names of internal properties used by the Session object)

Multiple sessions

If you want to use multiple sessions, you have to supply an array of options when registering the plugin. It supports the same options as a single session but in this case, the sessionName name is mandatory.

fastify.register(require('@fastify/secure-session'), [{
  sessionName: 'mySession',
  cookieName: 'my-session-cookie',
  key: fs.readFileSync(path.join(__dirname, 'secret-key')),
  cookie: {
    path: '/'
  }
}, {
  sessionName: 'myOtherSession',
  key: fs.readFileSync(path.join(__dirname, 'another-secret-key')),
  cookie: {
    path: '/path',
    maxAge: 100
  }
}])

fastify.post('/', (request, reply) => {
  request.mySession.set('data', request.body)
  request.myOtherSession.set('data', request.body)
  reply.send('hello world')
})

Using keys as strings

You can convert your key file to a hexadecimal string. This is useful in scenarios where you would rather load the key from an environment variable instead of deploying a file.

To convert a key file into a hexadecimal string you can do this in an npm script:

const keyBuffer = fs.readFileSync(path.join(__dirname, 'secret-key'));
const hexString = keyBuffer.toString('hex');
console.log(hexString) // Outputs: 4fe91796c30bd989d95b62dc46c7c3ba0b6aa2df2187400586a4121c54c53b85

To use your hexadecimal string with this plugin you would need convert it back into a Buffer:

fastify.register(require('@fastify/secure-session'), {
  key: Buffer.from(process.env.COOKIE_KEY, 'hex')
})

Note: key must be a secret key of length crypto_secretbox_KEYBYTES.

Security

  • Although the example reads the key from a file on disk, it is poor practice when it comes to security. Ideally, you should store secret/keys into a key management service like Vault, KMS or something similar and read them at run-time.
  • Use httpOnly session cookie for all production purposes to reduce the risk of session highjacking or XSS.

Using a secret

It is possible to generate a high-entropy key from a (low-entropy) secret passphrase. This approach is the simplest to use, but it adds a significant startup delay as strong cryptography is applied.

const fastify = require('fastify')({ logger: false })

fastify.register(require('@fastify/secure-session'), {
  secret: 'averylogphrasebiggerthanthirtytwochars',
  salt: 'mq9hDxBVDbspDR6n',
  cookie: {
    path: '/',
    httpOnly: true // Use httpOnly for all production purposes
    // options for setCookie, see https://github.com/fastify/fastify-cookie
  }
})

fastify.post('/', (request, reply) => {
  request.session.set('data', request.body)
  reply.send('session set')
})

fastify.get('/', (request, reply) => {
  const data = request.session.get('data')
  if (!data) {
    reply.code(404).send()
    return
  }
  reply.send(data)
})

fastify.get('/all', (request, reply) => {
  // get all data from session
  const data = request.session.data()
  if (!data) {
    reply.code(404).send()
    return
  }
  reply.send(data)
})

fastify.listen({ port: 3000 })

Using Keys with key rotation

It is possible to use an non-empty array for the key field to support key rotation as an additional security measure. Cookies will always be signed with the first key in the array to try to "err on the side of performance" however if decoding the key fails, it will attempt to decode using every subsequent value in the key array.

IMPORTANT: The new key you are trying to rotate to should always be the first key in the array. For example:

// first time running the app
fastify.register(require('@fastify/secure-session'), {
  key: [mySecureKey],

  cookie: {
    path: '/'
    // options for setCookie, see https://github.com/fastify/fastify-cookie
  }
})

The above example will sign and encrypt/decrypt sessions just fine. However, what if you want an extra security measure of being able to rotate your secret credentials for your application? This library supports this by allowing you to do the following:

// first time running the app
fastify.register(require('@fastify/secure-session'), {
  key: [myNewKey, mySecureKey],

  cookie: {
    path: '/'
    // options for setCookie, see https://github.com/fastify/fastify-cookie
  }
})

See that myNewKey was added to the first index position in the key array. This allows any sessions that were created with the original mySecureKey to still be decoded. The first time a session signed with an older key is "seen", by the application, this library will re-sign the cookie with the newest session key therefore improving performance for any subsequent session decodes.

To see a full working example, make sure you generate secret-key1 and secret-key2 alongside the js file below by running:

npx @fastify/secure-session > secret-key1
npx @fastify/secure-session > secret-key2
const fs = require('node:fs')
const fastify = require('fastify')({ logger: false })

const key1 = fs.readFileSync(path.join(__dirname, 'secret-key1'))
const key2 = fs.readFileSync(path.join(__dirname, 'secret-key2'))

fastify.register(require('@fastify/secure-session'), {
  // any old sessions signed with key2 will still be decoded successfully the first time and
  // then re-signed with key1 to keep good performance with subsequent calls
  key: [key1, key2],

  cookie: {
    path: '/'
    // options for setCookie, see https://github.com/fastify/fastify-cookie
  }
})

fastify.post('/', (request, reply) => {
  // will always be encrypted using `key1` with the configuration above
  request.session.set('data', request.body)
  reply.send('session set')
})

fastify.get('/', (request, reply) => {
  // will attempt to decode using key1 and then key2 if decoding with key1 fails
  const data = request.session.get('data')
  if (!data) {
    reply.code(404).send()
    return
  }
  reply.send(data)
})

fastify.listen({ port: 3000 })

WARNING: The more keys you have in the key array can make the decode operation get expensive if too many keys are used. at once. It is recommended to only use 2 keys at a given time so that the most decode attempts will ever be is 2. This should allow ample support time for supporting sessions with an old key while rotating to the new one. If you have really long lived sessions it could be possible to need to support 3 or even 4 keys. Since old sessions are re-signed with the key at the first index the next time they are seen by the application, you can get away with this. That first time the older session is decoded will be a little more expensive though.

For a full "start to finish" example without having to generate keys and setup a server file, see the second test case in the test file at /test/key-rotation.js in this repo.

Configuring cookie options inside a route

You can configure the options for setCookie inside a route by using the session.options() method.

fastify.post('/', (request, reply) => {
  request.session.set('data', request.body)
  // .options takes any parameter that you can pass to setCookie
  request.session.options({ maxAge: 60 * 60 }); // 3600 seconds => maxAge is always passed in seconds
  reply.send('hello world')
})

Integrating with other libraries

If you need to encode or decode a session in related systems (like say @fastify/websocket, which does not use normal Fastify Request objects), you can use @fastify/secure-session's decorators to encode and decode sessions yourself. This is less than ideal as this library's cookie setting code is battle tested by the community, but the option is there if you need it.

fastify.createSecureSession({ foo: 'bar' })
// => Session returns a session object for manipulating with .get and .set to then be encoded with encodeSecureSession

fastify.encodeSecureSession(request.session)
// => "abcdefg" returns the signed and encrypted cookie string, suitable for passing to a Set-Cookie header

fastify.decodeSecureSession(request.cookies['session'])
// => Session | null  returns a session object which you can use to .get values from if decoding is successful, and null otherwise

When using multiple sessions, you will have to provide the sessionName when encoding and decoding the session.

fastify.encodeSecureSession(request.session, 'mySecondSession')

fastify.decodeSecureSession(request.cookies['session'], undefined, 'mySecondSession')

Add TypeScript types

The session data is defined as an interface called SessionData. It can be extended with declaration merging for improved type support.

declare module '@fastify/secure-session' {
  interface SessionData {
    foo: string;
  }
}

fastify.get('/', (request, reply) => {
  request.session.get('foo'); // typed `string | undefined`
  reply.send('hello world')
})

When using a custom sessionName or using multiple sessions the types should be configured as follows:

interface FooSessionData {
  foo: string;
}

declare module "fastify" {
  interface FastifyRequest {
    foo: Session<FooSessionData>;
  }
}

fastify.get('/', (request, reply) => {
  request.foo.get('foo'); // typed `string | undefined`
  reply.send('hello world')
})

Security Notice

@fastify/secure-session stores the session within a cookie, and as a result an attacker could impersonate a user if the cookie is leaked. The maximum expiration time of the session is set by the expiry option, which has default 1 day. Adjust this parameter accordingly. Moreover, to protect users from further attacks, all cookies are created as "http only" if not specified otherwise.

License

MIT

fastify-secure-session's People

Contributors

airhorns avatar alexkar598 avatar antoine-coulon avatar bompus avatar climba03003 avatar delvedor avatar dependabot-preview[bot] avatar dependabot[bot] avatar eomm avatar fa-sharp avatar fdawgs avatar gehbt avatar github-actions[bot] avatar gurgunday avatar is2ei avatar johanmanders avatar john-royal avatar jsprw avatar jsumners avatar mcollina avatar pierbover avatar pkyeck avatar robinvdvleuten avatar salesh avatar salmanm avatar simoneb avatar srmarjani avatar uzlopak avatar xkal36 avatar zekth avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

fastify-secure-session's Issues

Add info about using keys as hex strings in the README

Sometimes deploy is being made from a repo (eg: Heroku) but it's not a great idea to commit key files.

A solution to not use low entropy strings would be to convert the generated key into a hex string and then convert it to a buffer when initializing the plugin.

To convert the key from buffer to a hex string;

const key = fs.readFileSync(path.join(__dirname, 'secret-key'));
const hex = key.toString('hex'));

And then something like:

fastify.register(fastifySecureSession, {
  key: Buffer.from(process.env.COOKIE_KEY, 'hex'),
});

Would you accept a PR to add this info to the README?

No native build was found - EsBuild AWS Lambda

Prerequisites

  • I have written a descriptive issue title
  • I have searched existing issues to ensure the issue has not already been raised

Issue

I understand that we are relying on a native module, so this might not be a straightforward approach to shoot and deploy; however, I was wondering if anyone could achieve a successful code build with fastify lambda and this package. Whenever using esbuild to bundle it I end up with the error No native build was found.

route example

Hi,

for some routes, I have small data session to save in cookie. sample code is as below. How do I modify this code to use fastify-secure-session?

const fastify = require('fastify')()

fastify.register(function (instance, options, next) {
fastify.get('/foo', function (req, reply) {
reply.send('no plugins affecting this route')
})
next()
})

fastify.register(function (instance, options, next) {
instance
.register(fastifyCookie)
.register(require('fastify-static'))
.register(require('fastify-multipart'))
.register(require('fastify-formbody'))
.get('/bar', function (req, reply) {
reply.send('several plugins affect this route')
})
next()
})

How to delete a session key?

Looking at the code, it doesn't seem possible to delete a key. All I can see is how to set it to null or empty string, which isn't great on my end for keeping a session cleaned up.

Would it be possible to add a .delete() or .remove() function, or possibly if you .set('myKey', null), it deletes the key from the session, but a dedicated function would probably be best to prevent any regression.

TypeScript rewrite?

๐Ÿš€ Feature Proposal

Might have some time to allocate to a full ts rewrite of the lib, (before working on the external store support), would you consider merging that?

Motivation

Would be great to have the typescript induced confidence!

Multiple cookies

Prerequisites

  • I have written a descriptive issue title
  • I have searched existing issues to ensure the feature has not already been requested

๐Ÿš€ Feature Proposal

Add support for different "instances" of the session plugin, with different cookie names and cookie options (different path/expiration date). This could be accomplished by allowing to specify the decorated field name (request.session by default) in plugin options.

Please keep in mind this will require changing the way types work, as the SessionData is currently set for the entire @fastify/secure-session module

Motivation

I need to keep a separate session for short-term (data expiring after closing tab) and long-term storage (user login token)

Example

const SecureSession = require('@fastify/secure-session');

fastify.register(SecureSession, {
  cookieName: 'long-term-cookie',
  cookie: {
    path: '/'
    expires: new Date('2137-01-01'),
  },
  field: 'longTermSession'
});
fastify.register(SecureSession, {
  cookieName: 'short-term-cookie',
  cookie: {
    path: '/'
    expires: undefined,
  },
  field: 'shortTermSession'
});

fastify.get('/', (request) => {
  console.log(request.longTermSession);
  console.log(request.shortTermSession);
});

changed value should be set to true when modifying objects within session

Prerequisites

  • I have written a descriptive issue title
  • I have searched existing issues to ensure the bug has not already been reported

Fastify version

4.26.2

Plugin version

7.1.0

Node.js version

18.8.2

Operating system

macOS

Operating system version (i.e. 20.04, 11.3, 10)

13.6.4

Description

Modifying objects in session does not set changed to true.

Steps to Reproduce

See passport-oauth2 - PKCESessionStore (code permalink attached)

https://github.com/jaredhanson/passport-oauth2/blob/be9bf58cee75938c645a9609f0cc87c4c724e7c8/lib/state/pkcesession.js#L48

req.session[key].state = sstate;

This line modifies an object within session, however session[key] is not proxied. Changing this value won't set changed to true.

Expected Behavior

changed should be set to true when modifying an object/array within session.

No way to update session expiration

Prerequisites

  • I have written a descriptive issue title
  • I have searched existing issues to ensure the issue has not already been raised

Issue

I got a little confused by this code snippet in the README:

fastify.get('/ping', (request, reply) => {
  request.session.options({maxAge: 3600})
  
  // Send the session cookie to the client even if the session data didn't change
  // can be used to update cookie expiration
  request.session.touch()
  reply.send('pong')
})

It turns out this does not change when the session expires, it only changes what Max-Age is sent to the browser. I looked around and didn't find a way to actually extend a session. Is this intentional, or is it a missing feature that could be added?

Allow for function to be passed in place of static key

I would like to rotate keys and the easiest way for an implementation like that would be to support passing in an overloaded parameter of type 'function' in order to get the keys we want used at runtime. Would you accept an PR for something like this?

Add a "proxy" flag to support setting the values directly on the session object.

Prerequisites

  • I have written a descriptive issue title
  • I have searched existing issues to ensure the feature has not already been requested

๐Ÿš€ Feature Proposal

In fastify/fastify-passport#491 and many others there is a need for setting the values natively on the session object itself. I think this could be achieved via the use of a Proxy.

Motivation

No response

Example

The following should be supported:

'use strict'

const fastify = require('fastify')({ logger: false })
const fs = require('fs')
const path = require('path')

fastify.register(require('fastify-secure-session'), {
  // the name of the session cookie, defaults to 'session'
  cookieName: 'my-session-cookie',
  // adapt this to point to the directory where secret-key is located
  key: fs.readFileSync(path.join(__dirname, 'secret-key')),
  proxy: true,
  cookie: {
    path: '/'
    // options for setCookie, see https://github.com/fastify/fastify-cookie
  }
})

fastify.post('/', (request, reply) => {
  request.session.data = request.body // or any other property that is not get, set or delete.
  reply.send('hello world')
})

fastify.get('/', (request, reply) => {
  const data = request.session.data
  if (!data) {
    reply.code(404).send()
    return
  }
  reply.send(data)
})

fastify.post('/logout', (request, reply) => {
  request.session.delete()
  reply.send('logged out')
})

Unable to forward session in request

Prerequisites

  • I have written a descriptive issue title
  • I have searched existing issues to ensure the bug has not already been reported

Fastify version

3.24.1

Plugin version

3.0.0

Node.js version

14.18.1

Operating system

macOS

Operating system version (i.e. 20.04, 11.3, 10)

12.0.1

Description

We are using Twitter Login with Passport (https://github.com/jaredhanson/passport-twitter)
A call is sent to Twitter with session object changes by the aforementioned library, and then when a callback request from Twitter is received at Fastify end, its session object is reset.

I am believing it has to do with fastify-secure-session. More details at jaredhanson/passport-twitter#109

Steps to Reproduce

Please follow jaredhanson/passport-twitter#109

Expected Behavior

Session object should not be reset and work properly

Log messages

Could you, please, add an option to don't log messages about session setting/non-changed/removing etc?
The message "fastify-secure-session: there is no session or the session didn't change, leaving it as is" has a little sense and just flooding logs.

Providing an empty array of keys does not throw an error

Prerequisites

  • I have written a descriptive issue title
  • I have searched existing issues to ensure the bug has not already been reported

Fastify version

3.27.1

Plugin version

4.1.1

Node.js version

16.14.0

Operating system

macOS

Operating system version (i.e. 20.04, 11.3, 10)

11.5.1

Description

Hey,

I'm currently implementing key rotation and I'm not sure if this is a bug or the expected behavior but when providing an empty array of keys in the plugin option key, the plugin is not throwing any error in the same way as when an invalid or empty key is provided (as a String or Buffer).

Consequently by providing an empty array of keys the plugin will be registered but will make the encode phase fail at runtime when trying to set something on the secure session.

For now, the check on Arrays is only about values inside the Array here:

key = key.map(ensureBufferKey)

When the Array is empty, it seems like no additional check is performed.

Steps to Reproduce

Take for instance this example which allows the plugin to be registered:

import FastifySecureSession from "@fastify/secure-session";

const fastify = require('fastify')({ logger: false });

fastify.register(FastifySecureSession, {
  cookieName: "session-cookie",
  key: [] // empty array of secret keys,
  cookie: {
    path: "/",
    maxAge: 3600,
    httpOnly: true,
  },
});

fastify.get('/encode', function (request, reply) {
  request.session.set('data', { someData: [] });
  reply.send("encode done");
});

fastify.listen(2000, (err) => {
  if (err) {
    process.exit(1);
  }
});

But when calling that endpoint /encode, this results in an Error k must be an instance of TypedArray when using sodium to encode the data.

Expected Behavior

The behavior I'm expecting is the same as when providing an invalid or empty Buffer/String i.e: throwing a kind of PluginRegistrationError when loading the plugin and not dealing with runtime errors once the plugin is registered.

For instance:

fastify.register(fastifySecureSession, {
  cookieName: "session-cookie",
  key: "" // invalid because empty,
  cookie: {
    path: "/",
    maxAge: 3600,
    httpOnly: true,
  },
});

Doing this would result in a key or secret must specified error.
This would allow the library to be consistent with the way of dealing with valid/invalid keys before registering the plugin.

I would be happy to open a PR if we all agree it's not the expected behavior ๐Ÿ˜„

Missing peer dependency on fastify

Prerequisites

  • I have written a descriptive issue title
  • I have searched existing issues to ensure the bug has not already been reported

Fastify version

latest

Plugin version

No response

Node.js version

x

Operating system

macOS

Operating system version (i.e. 20.04, 11.3, 10)

x

Description

There's no peer dependency on fastify, which can break things with stricter package managers like Yarn or pnpm.

Steps to Reproduce

See package.json

Expected Behavior

There should be a peer dependency on fastify. I could open a PR to add it myself, but not sure what the version range should be. Is "*" acceptable?

Allow for custom cookie options per session

For example: some users want their cookies to wipe after the session others want them to stick around for a week.

I think it is possible by extending the Session class and setting a new optional property that will then be referenced during the cookie response.

Would you consider this feature?

"k\" must be crypto_secretbox_KEYBYTES bytes long

Prerequisites

  • I have written a descriptive issue title
  • I have searched existing issues to ensure the issue has not already been raised

Issue

Hello guys,

I have a question regarding the current assertions implemented around each key length.

When registering the plugin and providing a key, assertions about that key (or key array) require that each key is atleast 32 bytes long here, here and here.

When providing for instance a key with 64 bytes, the key is considered valid at registration time:

// Ok
fastify.register(require('@fastify/secure-session'), {
  // 64 bytes
  key: Buffer.from('4b56344efdfd4afd0964fd27fd16877a4b56344efdfd4afd0964fd27fd16877a', 'utf-8'), 
}

But at runtime when creating the session, there is an error which appears to be thrown from libsodium "k\" must be crypto_secretbox_KEYBYTES bytes long (crypto_secretbox_KEYBYTES seems to be 32):

// Ko
fastify.post('/', (request, reply) => {
 // runtime error mentioned above
  request.session.set('data', { payload: "hello Antoine" })
  reply.send('hello world')
})

I am missing something here? Or we should just constraint the inputs keys to be strictly 32 bytes long to respect the libsodium constraint of crypto_secretbox_KEYBYTES and make the registration fail if any key is not strictly equal to 32 bytes ?

Thanks

README code snippets don't work without cookie path key

๐Ÿ› Bug Report

In all of the snippets in the README, the configuration option when registering the plugin does not specify a path key. Without this key, the plugin does not work at all.

To Reproduce

Copy any snippet as is into a fastify project, and sessions and cookies will not save properly.

Expected behavior

The snippets should at least include the minimal configuration needed for the plugin to work as intended. Just adding this below to the config object to each snippet would ensure people don't get stuck for 45~ minutes like I did ๐Ÿ‘

Maybe it makes sense to set this as a default value if it's not passed to the plugin config as well? That's up to you guys.

cookie: {
  path: '/',
}

Segmentation Fault when using alpine image

Prerequisites

  • I have written a descriptive issue title
  • I have searched existing issues to ensure the bug has not already been reported

Fastify version

4.0.0

Plugin version

5.3.0

Node.js version

18.x.x

Operating system

Linux

Operating system version (i.e. 20.04, 11.3, 10)

node:lts-alpine

Description

Hi,
i have been trying to implement azure ad login using the package @fastify/passport with passport-azure-ad which requires the use of @fastify/secure-session for session management but when ever i run my project in docker and try the azure ad login route i get Segmentation Fault.
i m using node-segfault-handler to catch the error.

i hv narrowed down the specific code causing the error bellow are the screenshots

image

image

Below is my dockerfile

FROM node:lts-alpine as dependencies
WORKDIR /usr/src/app
RUN apk add --update --no-cache python3 make g++
COPY package*.json ./
COPY ./patches ./patches
RUN npm config set update-notifier false
RUN npm install --loglevel=error

FROM node:lts-alpine as builder
WORKDIR /usr/src/app
COPY .env ./
# COPY secure-session-secret-key ./secure-session-secret-key
COPY . .
COPY --from=dependencies /usr/src/app/node_modules ./node_modules
RUN npm config set update-notifier false
RUN apk add --update --no-cache openssl1.1-compat
RUN npx prisma generate
RUN npm run build:ts --loglevel=error

FROM node:lts-alpine as runner
WORKDIR /usr/src/app
ENV NODE_ENV production
RUN npm config set update-notifier false
RUN npm i -g fastify-cli --loglevel=error
RUN npm i -g pm2 --loglevel=error
RUN npm i -g typescript --loglevel=error
RUN npx @fastify/secure-session --yes >secure-session-secret-key

COPY --from=builder /usr/src/app/.env ./
# COPY --from=builder /usr/src/app/secure-session-secret-key ./secure-session-secret-key
COPY --from=builder /usr/src/app/dist ./dist
COPY --from=builder /usr/src/app/node_modules ./node_modules
COPY --from=builder /usr/src/app/package.json ./package.json
COPY --from=builder /usr/src/app/manifests ./manifests
RUN apk add --update --no-cache openssl1.1-compat
RUN npx prisma generate
#RUN cat .env

EXPOSE 5000
CMD ["pm2-runtime", "start", "manifests/dev/ecosystem.config.js"]

BTW when i run without docker just on my pc , it works , no errors

Steps to Reproduce

visiting below route gives Segmentation Fault error and crashes the api server when the project ran in docker

image

Expected Behavior

ideally ot should redirect to microsoft for azure login if i visit this route below in screenshot

image

External store support

๐Ÿš€ Feature Proposal

Is external store support (eg. redis) on the roadmap?

Motivation

Would love to try this in production but would require to store session in a shared DB.

Example

fastify.register(require('fastify-secure-session'), {
  store: IS_TEST ? new MemoryStore() : new RedisStore({ client: new Redis(REDIS_URI), ttl: SESSION_TTL }),
})

Release new version to be type compatible with other `@fastify/cookie` modules

Prerequisites

  • I have written a descriptive issue title
  • I have searched existing issues to ensure the issue has not already been raised

Issue

Using the current latest version of this module and of @fastify/oauth2 causes type errors as they rely on two different major versions of @fastify/cookie

#194 merged an update, but its yet to be released.

Releasing that as eg. 6.2.1 would be very nice ๐Ÿ‘

Key generation script does not work on WIndows

Prerequisites

  • I have written a descriptive issue title
  • I have searched existing issues to ensure the bug has not already been reported

Fastify version

v3.21.0

Plugin version

latest

Node.js version

14.x

Operating system

Windows

Operating system version (i.e. 20.04, 11.3, 10)

not WSL

Description

The key generation script does not work on Windows.

Steps to Reproduce

run the key generation script

Expected Behavior

No response

Add support for typed session data

Prerequisites

  • I have written a descriptive issue title
  • I have searched existing issues to ensure the feature has not already been requested

๐Ÿš€ Feature Proposal

I'd like to type the data I put in and get out of the session.

Motivation

I don't like type-casting any on every session.get().

Example

// fastify-secure-session/index.d.ts
export interface Session {
  // โ€ฆ
  get<Key extends keyof SessionData>(key: Key): SessionData[Key] | undefined;
  set<Key extends keyof SessionData>(key: Key, value: SessionData[Key] | undefined): void;
}

export interface SessionData {
  [key: string]: any;
}
# user code
declare module 'fastify-secure-session' {
  interface SessionData {
    codeVerifier: string;
    tokenSet: TokenSet;
  }
}

Error: Cannot find module 'sodium-universal'

Version: 0.4.2

Command

Stack trace

internal/modules/cjs/loader.js:573
    throw err;
    ^

Error: Cannot find module 'sodium-universal'
    at Function.Module._resolveFilename (internal/modules/cjs/loader.js:571:15)
    at Function.Module._load (internal/modules/cjs/loader.js:497:25)
    at Module.require (internal/modules/cjs/loader.js:626:17)
    at require (internal/modules/cjs/helpers.js:20:18)
    at Object.<anonymous> (/home/MY_WORKING_DIR/node_modules/fastify-secure-session/genkey.js:5:16)
    at Module._compile (internal/modules/cjs/loader.js:678:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:689:10)
    at Module.load (internal/modules/cjs/loader.js:589:32)
    at tryModuleLoad (internal/modules/cjs/loader.js:528:12)
    at Function.Module._load (internal/modules/cjs/loader.js:520:3)

Entry in package-lock.json

   "fastify-secure-session": {
      "version": "0.4.2",
      "resolved": "https://registry.npmjs.org/fastify-secure-session/-/fastify-secure-session-0.4.2.tgz",
      "integrity": "sha512-s72gxue4fobJM+WzrdeOBFtmjVnwOLCiTnzrMem8nynVTLCW4WPCByQJdpnSvKrUwhBTlcLyhRksGg3iaOr69g==",
      "requires": {
        "fastify-cookie": "2.0.1",
        "fastify-plugin": "1.1.3",
        "sodium-native": "2.1.6"
      },
      "dependencies": {
        "fastify-plugin": {
          "version": "1.1.3",
          "resolved": "https://registry.npmjs.org/fastify-plugin/-/fastify-plugin-1.1.3.tgz",
          "integrity": "sha512-pLV6JzcfbGipYsSlS9BLWs5nnIBxbmf1MszmwUPWVnrARJHr4vlcOHL/vxcK/bnQXIBAVOeWWgnFkOTsmPATow==",
          "requires": {
            "semver": "5.5.0"
          }
        }
      }
    },

Add method to get all data in session

Prerequisites

  • I have written a descriptive issue title
  • I have searched existing issues to ensure the feature has not already been requested

๐Ÿš€ Feature Proposal

Other session modules, both for fastify and other libraries, provide a way to get all data from the current session. Some use a dedicated data() method or by calling get() without a key.

Motivation

No response

Example

No response

typescript types don't work properly

Prerequisites

  • I have written a descriptive issue title
  • I have searched existing issues to ensure the bug has not already been reported

Fastify version

4.25.1

Plugin version

7.1.0

Node.js version

20.9.0

Operating system

Windows

Operating system version (i.e. 20.04, 11.3, 10)

10

Description

The types don't work properly.
e.g.:

declare module "@fastify/secure-session" {
  interface SessionData {
    userID: number;
  }
}

async function login(
  request: FastifyRequest,
  reply: FastifyReply,
): Promise<FastifyReply> {
  request.session.set("usersID", 123);
}

In the above code snippet, we made a typo, and typed it as "usersID" instead of "userID". Oops! But we don't get a compiler error - it just works, and the bug makes its way to production.

Is there some way for a declaration merge to get rid of the string index signature? Because that's the root cause of the bug.

New cookie is made on every request, even if session is unchanged

Prerequisites

  • I have written a descriptive issue title
  • I have searched existing issues to ensure the bug has not already been reported

Fastify version

3.27.4

Plugin version

4.1.1

Node.js version

16.x

Operating system

Linux

Operating system version (i.e. 20.04, 11.3, 10)

Ubuntu 20.04.4 LTS

Description

I recently updated from fastify-secure-session v3.0.0 to v4.1.1. I'm now finding that even if there are no changes made to the Session data, a new cookie/session is being issued on every request.

With some debugging that I did, I suspect the issue is in the Proxy wrapper around the Session object, and how it interacts with the Session's changed and deleted properties. For example, when calling session.changed = signingKeyRotated (line 150 below), the Proxy wrapper calls the 'set' method on the Session, and the changed property is added to the actual Session data. And therefore the library thinks that the Session has been changed on every request, and issues a new cookie.

const session = new Proxy(new Session(JSON.parse(msg)), sessionProxyHandler)
session.changed = signingKeyRotated
return session

This might happen in other places where session.changed or session.deleted is modified as well. Unfortunately I don't know enough about how Proxy works to know how to fix this (I would make a PR if I did!)

Steps to Reproduce

  1. Enable 'trace' logging for fastify
  2. Register fastify-secure-session plugin
  3. Create a new session and get the cookie
  4. Make a request using the cookie, but don't make any changes to the session in the route handler (don't call session.set(), or session.foo = bar, etc.
  5. fastify-secure-session reports that changes have been made to the session, and a new cookie is issued and sent to the user.

Expected Behavior

A new cookie/session should not be issued if there are no changes made to the session data. Also, the changed property should not be added to the session data itself.

New "expiry" is not included in TypeScript definition

Prerequisites

  • I have written a descriptive issue title
  • I have searched existing issues to ensure the bug has not already been reported

Fastify version

4.26.2

Plugin version

7.5.0

Node.js version

20.10.0

Operating system

Windows

Operating system version (i.e. 20.04, 11.3, 10)

10

Description

New expiry options from 7.3.0 is not added to TypeScript definition

Steps to Reproduce

See types/index.d.ts

Expected Behavior

No response

Considering adding proprietary cookies good practices as Chrome make big changes on cookies in 2024

Prerequisites

  • I have written a descriptive issue title
  • I have searched existing issues to ensure the feature has not already been requested

๐Ÿš€ Feature Proposal

Third party cookies won't be supported anymore as 2024 Chrome said

Chrome recommend good practices even for proprietary cookies to ensure it continues to work for session but for now theses options are unsupported in fastify-secure-session :

  • secure: true
  • __Host-cookie-name=cookie-value
  • SameSite=Strict || Lax

Motivation

ensure session cookies for the plugin remain practicable

Example

app.register(fastifySecureSession, {
    **_secure: true,
    __Host-cookie-name=cookie-value
    SameSite=Strict_**
    cookieName: 'session',
    key: readFileSync(join(rootDir, 'secret-key')),
    cookie: {
        path: '/',
    }
})

"reply.signCookie is not a function" when setting option signed: true

Prerequisites

  • I have written a descriptive issue title
  • I have searched existing issues to ensure the bug has not already been reported

Fastify version

4.26.2

Plugin version

7.1.0

Node.js version

14.18.1

Operating system

Windows

Operating system version (i.e. 20.04, 11.3, 10)

10

Description

Setting the option signed: true when initializing @fastify/secure-session or setting the same option signed: true when using the setCookie function, you get an error: "reply.signCookie is not a function".

Example

const fastify = require("fastify")({ logger: true });
const fs = require("node:fs");
const path = require("node:path");

fastify.register(require("@fastify/secure-session"), {
  key: fs.readFileSync(path.join(__dirname, "secret.key")),
  cookie: {
    secure: true,
    httpOnly: true,
    path: "/",
    signed: true,
  },
});

fastify.get("/", function (request, reply) {
  /**
   * Both examples below won't work because of signed: true in cookie options.
   * The error: "reply.signCookie is not a function"
   */

  // Example 1: setting session variable
  request.session.set("my-session-variable", "some-value");

  // Example 2: setting cookie
  reply.setCookie("my-cookie", "some-value", {
    httpOnly: true,
    path: "/",
    secure: true,
    signed: true,
  });

  return "done";
});

fastify.listen({ port: 3001 }, function (err, address) {
  if (err) {
    fastify.log.error(err);
    process.exit(1);
  }
});

What happens

This following happens inside the @fastify/secure-session index.js file (simplyfied):

// defaultSecret is later used to set secret for @fastify/cookie
let defaultSecret

for (const sessionOptions of options) {
    let key

    if (sessionOptions.secret) {
        /**
         * In our example this code gets skipped, because we did not set a secret (and salt), but used a key
         * when initializing @fastify/secure-session
         */

        // defaultSecret is set using sessionOptions.secret
        if (!defaultSecret) {
            defaultSecret = sessionOptions.secret
        }

        // key is set using secret (and salt), code is not important for this example
    }

    if (sessionOptions.key) {
        /**
         * In our example this code gets executed, because we did set a key
         * when initializing @fastify/secure-session
         */
    }
}

if (fastify.hasPlugin('@fastify/cookie')) {
    /**
     * This code gets skipped, because we did not initialize @fastify/cookie before @fastify/secure-session
     */ 
} else {
    /**
     * This code gets executed in our example.
     * 
     * Because the secret will stay empty, later on the signCookie function will be removed, so we can't use signCookie.
     */ 
    fastify
        .register(require('@fastify/cookie'), {
            secret: defaultSecret
        })
        .register(fp(addHooks))
}

Possible solution

I think one of the possible solutions could be to change from:

if (sessionOptions.secret) {
  // setting defaultSecret and key
}
if (sessionOptions.key) {
  // setting key
}

to something like:

if (sessionOptions.key) {
  // setting key
  // derive defaultSecret from key
}
if (!key) {
  if (sessionOptions.secret) {
    // setting defaultSecret
  }
}

Steps to Reproduce

I have set up an example project in CodeSandBox: fastify-secure-session-error-example

Expected Behavior

No response

Passing `signed: true` in options breaks session decoding.

๐Ÿ› Bug Report

Passing signed: true (I know that this makes not too much sense) to underlying fastify-cookie breaks session decoding.

To Reproduce

Steps to reproduce the behavior:

await app.register(fastifySecureSession, {
    // the name of the session cookie, defaults to 'session'
    cookieName: 'ses',
    // adapt this to point to the directory where secret-key is located
    key: await fs.readFile('key-file'),
    cookie: {
      signed: true,
    },
  });

In this case fastify-cookie signature will be counted as a part of nonce https://github.com/fastify/fastify-secure-session/blob/master/index.js#L96 and decoding will fail

Expected behaviour

Maybe it worth to mention this in docs or somewhere else until signing will be fully implemented. Or signature(all that goes after the .) could be removed from nonce part

Recommend way to decorate secure-session

Prerequisites

  • I have written a descriptive issue title
  • I have searched existing issues to ensure the issue has not already been raised

Issue

Hi, I've successfully managed to integrate fastify-passport and fastify-secure-session. I'm able to make oauth calls and have the data stored through registerUserDeserializer and registerUserSerializer. I'm using this to encode user information and authentication.

I'd like to protect certain routes with secure session but I'm not sure what the best practice is, i.e.

routes/
....auth/ (contains index.js where secure-session is registered)
....data1/ (provides a protected resource)
....data2/ (provides a public resource)

I thought fastify.register encapsulation does not apply to children but this does not work:

routes/
....auth/ (contains index.js where secure-session is registered)
........data1/ (provides a protected resource)
....data2/ (provides a public resource)
  1. registerUserDeserializer is not called when accessing routes in data1/
  2. accessing request.session.get, I see the following error: Cannot read property 'get' of undefined - which is somewhat expected if the passport and secure-session context is limited to auth/ folder only

Is there a way to make request.session exposed or structure the app?

"No native build was found"

Prerequisites

  • I have written a descriptive issue title
  • I have searched existing issues to ensure the bug has not already been reported

Fastify version

4.17.0

Plugin version

6.1.0

Node.js version

18.16.0

Operating system

macOS

Operating system version (i.e. 20.04, 11.3, 10)

12.6.5

Description

Cannot execute my server because of this error (it seems related to sodium-native though):

Error: No native build was found for platform=darwin arch=x64 runtime=node abi=108 uv=1 libc=glibc node=18.16.0 webpack=true
    loaded from: /var/opt/src/my_server/dist

    at load.resolve.load.path (/var/opt/src/my_server/dist/server.cjs:217977:9)
    at load (/var/opt/src/my_server/dist/server.cjs:217939:30)
    at ./node_modules/sodium-native/index.js (/var/opt/src/my_server/dist/server.cjs:288036:101)
    at __webpack_require__ (/var/opt/src/my_server/dist/server.cjs:393084:42)
    at ./node_modules/@fastify/secure-session/index.js (/var/opt/src/my_server/dist/server.cjs:4935:16)
    at __webpack_require__ (/var/opt/src/my_server/dist/server.cjs:393084:42)
    at ./src/passport.js (/var/opt/src/my_server/dist/server.cjs:337150:81)
    at __webpack_require__ (/var/opt/src/my_server/dist/server.cjs:393084:42)
    at ./src/api/Logs.js (/var/opt/src/my_server/dist/server.cjs:330342:70)
    at __webpack_require__ (/var/opt/src/my_server/dist/server.cjs:393084:42)

I have tried to transpile and run with node 16.20.0 and 14.21.3, and also with @fastify/secure-session 5.3.0.

If I do not include @fastify/secure-session the app runs fine.

Steps to Reproduce

I have created a repository: https://github.com/monteiz/fastify_secure_session_issue

Expected Behavior

Run without errors.

UX Bug

Very excited to see sodium-universal being used! I have a small UX nitpick:

https://github.com/mcollina/fastify-secure-session/blob/01734d85b1dace238ecec9a41b1dd474af59cdd1/index.js#L8-L10

This should be exactly KEYBYTES long, as only those bytes will be used. The error message implies that a longer key can be used, but in that case it will just be truncated. We allow larger buffers from our side as to not make any assumptions on behalf of users. I actually think we should add a section in sodium-native docs pointing this out

Another point worth noting is that the key should either be random bytes, or have gone though a KDF with a moderate to high setting before use, so it is hard to guess. When exposing the option of picking a key to users, they will think this is the same as a password, which it is not ๐Ÿ˜„ If you can restrict your usage to sodium-native, using the secure buffer api (sodium_malloc) and making the key sodium_mprotect_readonly, would also help keep the key even safer!

can't set options to fastify-cookie

Prerequisites

  • I have written a descriptive issue title
  • I have searched existing issues to ensure the bug has not already been reported

Fastify version

8.2.3

Plugin version

3.0.0

Node.js version

16.13.1

Operating system

macOS

Operating system version (i.e. 20.04, 11.3, 10)

12.0.1

Description

As I need to use cookieSigned, I need to register fastify-cookie to configure the secret

An The decorator 'parseCookie' has already been added! error occurs when registering both fastify-cookie and fastify-secure-session.

Steps to Reproduce

fastify.register(fastifyCookie,{ secret: 'xxx' })
fastify.register(secureSession,{ key: 'xxx' })

Expected Behavior

Add FastifyCookieOptions to secureSession, or avoid duplicate register fastify-cookie

Enable multiple cookie sessions

Prerequisites

  • I have written a descriptive issue title
  • I have searched existing issues to ensure the feature has not already been requested

๐Ÿš€ Feature Proposal

I'm using fastify-secure-session with fastify-passport like a identity provider for multiple pages. The problem is that there is only one cookieName in the configuration. Is it possible to use something like this:

// before
  fastify.register(fastifySecureSession, {
    key: fs.readFileSync(path.join(__dirname, 'secret-key')),
    cookieName: global.cookie_token_name,
    // options for setCookie of fastify-cookie
    cookie: {
      path: '/',
      httpOnly: is_prod,
      signed: is_prod
    }
  });

// after
  fastify.register(fastifySecureSession, {
    key: fs.readFileSync(path.join(__dirname, 'secret-key')),
    cookies: [
      {name: global.cookie_token_name, options: {path: '/admin', httpOnly: true, secure: is_prod}},
      {name: global.cookie_token_name2, options: {path: '/', httpOnly: true, secure: is_prod}},
    ]
  });

Motivation

No response

Example

No response

Upgrade @fastify/cookie to 9.1.0

Prerequisites

  • I have written a descriptive issue title
  • I have searched existing issues to ensure the bug has not already been reported

Fastify version

4.24.3

Plugin version

7.1.0

Node.js version

20.7.0

Operating system

macOS

Operating system version (i.e. 20.04, 11.3, 10)

14

Description

Right now I'm getting deprecation warnings that look like this:

(node:98534) [FSTDEP019] FastifyDeprecation: reply.context property access is deprecated. Please use "reply.routeOptions.config" or "reply.routeOptions.schema" instead for accessing Route settings. The "reply.context" will be removed in `fastify@5`.
(Use `node --trace-warnings ...` to show where the warning was created)

I traced it back to the fact that this plugin currently relies on @fastify/cookie 9.0.4, and context is no longer used in @fastify/cookie 9.1.0.

Steps to Reproduce

  • Use @fastify/secure-session 7.1.0 in a project.

Expected Behavior

It shouldn't print a deprecation warning.

Error: Cannot find module 'sodium-universal'

Version: 0.4.2

Command

Stack trace

internal/modules/cjs/loader.js:573
    throw err;
    ^

Error: Cannot find module 'sodium-universal'
    at Function.Module._resolveFilename (internal/modules/cjs/loader.js:571:15)
    at Function.Module._load (internal/modules/cjs/loader.js:497:25)
    at Module.require (internal/modules/cjs/loader.js:626:17)
    at require (internal/modules/cjs/helpers.js:20:18)
    at Object.<anonymous> (/home/MY_WORKING_DIR/node_modules/fastify-secure-session/genkey.js:5:16)
    at Module._compile (internal/modules/cjs/loader.js:678:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:689:10)
    at Module.load (internal/modules/cjs/loader.js:589:32)
    at tryModuleLoad (internal/modules/cjs/loader.js:528:12)
    at Function.Module._load (internal/modules/cjs/loader.js:520:3)

Entry in package-lock.json

   "fastify-secure-session": {
      "version": "0.4.2",
      "resolved": "https://registry.npmjs.org/fastify-secure-session/-/fastify-secure-session-0.4.2.tgz",
      "integrity": "sha512-s72gxue4fobJM+WzrdeOBFtmjVnwOLCiTnzrMem8nynVTLCW4WPCByQJdpnSvKrUwhBTlcLyhRksGg3iaOr69g==",
      "requires": {
        "fastify-cookie": "2.0.1",
        "fastify-plugin": "1.1.3",
        "sodium-native": "2.1.6"
      },
      "dependencies": {
        "fastify-plugin": {
          "version": "1.1.3",
          "resolved": "https://registry.npmjs.org/fastify-plugin/-/fastify-plugin-1.1.3.tgz",
          "integrity": "sha512-pLV6JzcfbGipYsSlS9BLWs5nnIBxbmf1MszmwUPWVnrARJHr4vlcOHL/vxcK/bnQXIBAVOeWWgnFkOTsmPATow==",
          "requires": {
            "semver": "5.5.0"
          }
        }
      }
    },

salt must be length 24

I get the error message "salt must be length 24" with a salt of length 24 (as measured by .length and Buffer.byteLength()

I checked sodium.crypto_pwhash_SALTBYTES on my system and it returns 16. However, a 16 character salt still doesn't work.

`.bin` is not registered when using yarn

Prerequisites

  • I have written a descriptive issue title
  • I have searched existing issues to ensure the regression has not already been reported

Last working version

4.1.0

Stopped working in version

4.1.1

Node.js version

18.x

Operating system

Linux

Operating system version (i.e. 20.04, 11.3, 10)

20.04

๐Ÿ’ฅ Regression Report

yarn do not put the bin file inside .bin folder.
So, it is unavailable to use either yarn or npx to execute genkey.js when you use yarn as package manager.

I don't know if it is expected behavior for yarn.
Some related information is that yarn only consider /^(?!\.{0,2}$)[a-z0-9._-]+$/i as valid bin.

Steps to Reproduce

npm init
yarn add @fastify/secure-session
yarn @fastify/secure-session // fail
npx @fastify/secure-session // fail

Expected Behavior

No response

Update cookie expiration without updating data

Prerequisites

  • I have written a descriptive issue title
  • I have searched existing issues to ensure the feature has not already been requested

๐Ÿš€ Feature Proposal

A touch() method (like in @fastify/session) to extend to cookie expiration date, without changing the session data.
This could be done by setting changed=true.

Motivation

It's useful in scenarios where the session is extended evey time the client calls some endpoints.

Example

Whenever we want to extend the session, we would do:

request.session.touch();

\"k\" must be crypto_secretbox_KEYBYTES bytes long issue

Prerequisites

  • I have written a descriptive issue title
  • I have searched existing issues to ensure it has not already been reported

Fastify version

3.16.1

Plugin version

2.3.1

Node.js version

14.16.1

Operating system

Windows

Operating system version (i.e. 20.04, 11.3, 10)

10

Description

Im trying to make a fastify application using passport. I found https://github.com/fastify/fastify-passport and tried to use it. For an unkown reason i get this issue \"k\" must be crypto_secretbox_KEYBYTES bytes long . Im posting the issue on this repository because i saw this issue fastify/fastify#2719

Steps to Reproduce

Im registering the session using process env (which is not the reason)

server.register(fastifySecureSesstion, {
  key: process.env.SECRET!,
});

After thats done I initialize passport.js, following fastify's example.

server.register(passport.initialize());
server.register(passport.secureSession());

In my request i set this as authentication strategy.

Expected Behavior

I expected the request to work without error, and log me into my account.

Missing genKey.js for npm install

Hi Matteo,

I am struggling to get this working.

npm i fastify-secure-session errs with following message on top of the stack.

npm ERR! path /home/dennis/Git/xyz/node_modules/fastify-secure-session/genKey.js

Is this a dependency which I need to install manually?

How do I set the expiration time for a separate Session

Prerequisites

  • I have written a descriptive issue title
  • I have searched existing issues to ensure the feature has not already been requested

๐Ÿš€ Feature Proposal

It appears that setting an expiration time is globally valid

For example, set an expiration time of 60 seconds
request.session.options({ maxAge:60 })

After 60 seconds, all messages will be cleared. How do I set the expiration time of a KEY by setting a separate KEY?

Motivation

No response

Example

No response

v5.3.0 breaks with `Cannot read properties of undefined (reading 'sign')"`

Prerequisites

  • I have written a descriptive issue title
  • I have searched existing issues to ensure the bug has not already been reported

Fastify version

4.9.2

Plugin version

5.3.0

Node.js version

16.10.0

Operating system

macOS

Operating system version (i.e. 20.04, 11.3, 10)

12.6

Description

We bumped the package to 5.3.0 and immediately experienced the Cannot read properties of undefined (reading 'sign')" error.

I then investigated this issue.
It comes from changes in @fastify/cookie and the fact that @fastify/secure-session now relies on @fastify/[email protected] whereas it was using @fastify/[email protected] before.

The error comes from the fastifyCookieSetCookie method especially those lines
https://github.com/fastify/fastify-cookie/blob/8d3feb35ab82016554d718fc4a450bd828227bcf/plugin.js#L14-L16

if (opts.signed) {
    value = signer.sign(value)
  }

Obviously the error comes from the fact that signer is undefined.
Why is that?

It's because fastifyCookieSetCookie is called with signer as undefined whereas in 5.2.0 it was not. And it is undefined because when the plugin is initialized signer is never set due to changes in @fastify/[email protected].

We are going to analyse the plugin function of @fastify/cookie which is always initialized with an empty options params in the context of @fastify/secure-session (at least in our case). (options = {})

In @fastify/[email protected] the plugin function starts like this

function plugin (fastify, options, next) {
  const secret = options.secret || ''
  const enableRotation = Array.isArray(secret)
  const algorithm = options.algorithm || 'sha256'
  const signer = typeof secret === 'string' || enableRotation ? new Signer(secret, algorithm) : secret

So, options is empty and the || case will assign empty string '' to secret and signer will become new Signer(secret, algorithm), we can sign cookies!

In @fastify/[email protected] the plugin function starts like this

function plugin (fastify, options, next) {
  const secret = options.secret
  const hook = getHook(options.hook)
  if (hook === undefined) {
    return next(new Error('@fastify/cookie: Invalid value provided for the hook-option. You can set the hook-option only to false, \'onRequest\' , \'preParsing\' , \'preValidation\' or \'preHandler\''))
  }
  const isSigner = !secret || (typeof secret.sign === 'function' && typeof secret.unsign === 'function')
  const algorithm = options.algorithm || 'sha256'
  const signer = isSigner ? secret : new Signer(secret, algorithm)

options is empty so secret is undefined.
isSigner is true because of !undefined.
signer is undefined because isSigner is true and secret is undefined.

That's how we end up with an undefined signer and a crashing lib :)

Steps to Reproduce

Use latest version of the package and try to sign a cookie. It will crash.
We bootstrap secureSession like that (NestJS app)

await app.register(secureSession, {
    secret: 'secret-string',
    salt: 'salt',
  })

Expected Behavior

I don't know if it's on the cookie lib or the fact that options are always empty but the release is not working for us :(
I'm wondering if the issue is not more important than that because even on 5.2.0 it looks like we sign cookie with an empty string as the secret which is...bad?
Regards :)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.