Skip to content

Commit

Permalink
feat: options to customize cookie names (#272)
Browse files Browse the repository at this point in the history
* Options to customize cookie names

* Apply PR code suggestions

---------

Co-authored-by: Vladimir Tkac <vladimir.tkac@sk.ibm.com>
  • Loading branch information
vtkac and Vladimir Tkac authored Oct 16, 2024
1 parent 1094c28 commit 3b1ab83
Show file tree
Hide file tree
Showing 5 changed files with 186 additions and 8 deletions.
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,17 @@ fastify.register(oauthPlugin, {
})
```

Additionally, you can customize the names of the cookies by setting the `redirectStateCookieName` and `verifierCookieName` options.
The default values for these cookies are `oauth2-code-verifier` for `verifierCookieName` and `oauth2-redirect-state` for `redirectStateCookieName`.

```js
fastify.register(oauthPlugin, {
...,
redirectStateCookieName: 'custom-redirect-state',
verifierCookieName: 'custom-code-verifier'
})
```

### Preset configurations

You can choose some default setup to assign to `auth` option.
Expand Down
40 changes: 32 additions & 8 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@ const kGenerateCallbackUriParams = Symbol.for('fastify-oauth2.generate-callback-

const { promisify, callbackify } = require('node:util')

const DEFAULT_VERIFIER_COOKIE_NAME = 'oauth2-code-verifier'
const DEFAULT_REDIRECT_STATE_COOKIE_NAME = 'oauth2-redirect-state'
const USER_AGENT = 'fastify-oauth2'
const VERIFIER_COOKIE_NAME = 'oauth2-code-verifier'
const PKCE_METHODS = ['S256', 'plain']

const random = (bytes = 32) => randomBytes(bytes).toString('base64url')
Expand All @@ -25,7 +26,10 @@ function defaultGenerateStateFunction (request, callback) {

function defaultCheckStateFunction (request, callback) {
const state = request.query.state
const stateCookie = request.cookies['oauth2-redirect-state']
const stateCookie =
request.cookies[
this.redirectStateCookieName
]
if (stateCookie && state === stateCookie) {
callback()
return
Expand Down Expand Up @@ -98,6 +102,20 @@ function fastifyOauth2 (fastify, options, next) {
if (!options.discovery && !options.credentials.auth) {
return next(new Error('options.discovery.issuer or credentials.auth have to be given'))
}
if (
options.verifierCookieName &&
typeof options.verifierCookieName !== 'string'
) {
return next(new Error('options.verifierCookieName should be a string'))
}
if (
options.redirectStateCookieName &&
typeof options.redirectStateCookieName !== 'string'
) {
return next(
new Error('options.redirectStateCookieName should be a string')
)
}
if (!fastify.hasReplyDecorator('cookie')) {
fastify.register(require('@fastify/cookie'))
}
Expand All @@ -116,10 +134,16 @@ function fastifyOauth2 (fastify, options, next) {
tokenRequestParams = {},
scope,
generateStateFunction = defaultGenerateStateFunction,
checkStateFunction = defaultCheckStateFunction,
checkStateFunction = defaultCheckStateFunction.bind({
redirectStateCookieName:
configured.redirectStateCookieName ||
DEFAULT_REDIRECT_STATE_COOKIE_NAME
}),
startRedirectPath,
tags = [],
schema = { tags }
schema = { tags },
redirectStateCookieName = DEFAULT_REDIRECT_STATE_COOKIE_NAME,
verifierCookieName = DEFAULT_VERIFIER_COOKIE_NAME
} = configured

if (userAgent) {
Expand Down Expand Up @@ -153,7 +177,7 @@ function fastifyOauth2 (fastify, options, next) {
return
}

reply.setCookie('oauth2-redirect-state', state, cookieOpts)
reply.setCookie(redirectStateCookieName, state, cookieOpts)

// when PKCE extension is used
let pkceParams = {}
Expand All @@ -164,7 +188,7 @@ function fastifyOauth2 (fastify, options, next) {
code_challenge: challenge,
code_challenge_method: configured.pkce
}
reply.setCookie(VERIFIER_COOKIE_NAME, verifier, cookieOpts)
reply.setCookie(verifierCookieName, verifier, cookieOpts)
}

const urlOptions = Object.assign({}, generateCallbackUriParams(callbackUriParams, request, scope, state), {
Expand Down Expand Up @@ -227,7 +251,7 @@ function fastifyOauth2 (fastify, options, next) {

function getAccessTokenFromAuthorizationCodeFlowCallbacked (request, reply, callback) {
const code = request.query.code
const pkceParams = configured.pkce ? { code_verifier: request.cookies['oauth2-code-verifier'] } : {}
const pkceParams = configured.pkce ? { code_verifier: request.cookies[verifierCookieName] } : {}

const _callback = typeof reply === 'function' ? reply : callback

Expand Down Expand Up @@ -299,7 +323,7 @@ function fastifyOauth2 (fastify, options, next) {
}

function clearCodeVerifierCookie (reply) {
reply.clearCookie(VERIFIER_COOKIE_NAME, cookieOpts)
reply.clearCookie(verifierCookieName, cookieOpts)
}

const pUserInfo = promisify(userInfoCallbacked)
Expand Down
139 changes: 139 additions & 0 deletions test/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2920,3 +2920,142 @@ t.test('options.checkStateFunction', t => {

t.end()
})

t.test('options.redirectStateCookieName', (t) => {
t.plan(2)

t.test('should be a string', (t) => {
t.plan(1)

const fastify = createFastify({ logger: { level: 'silent' } })

fastify
.register(
fastifyOauth2, {
name: 'the-name',
credentials: {
client: {
id: 'my-client-id',
secret: 'my-secret'
},
auth: fastifyOauth2.GITHUB_CONFIGURATION
},
callbackUri: '/callback',
redirectStateCookieName: 42
}
)
.ready((err) => {
t.strictSame(
err.message,
'options.redirectStateCookieName should be a string'
)
})
})

t.test('with custom cookie name', (t) => {
t.plan(4)

const fastify = createFastify({ logger: { level: 'silent' } })

fastify.register(fastifyOauth2, {
name: 'the-name',
credentials: {
client: {
id: 'my-client-id',
secret: 'my-secret'
},
auth: fastifyOauth2.GITHUB_CONFIGURATION
},
callbackUri: '/callback',
startRedirectPath: '/login',
redirectStateCookieName: 'custom-redirect-state'
})

t.teardown(fastify.close.bind(fastify))

fastify.inject(
{
method: 'GET',
url: '/login'
},
function (err, responseEnd) {
t.error(err)

t.equal(responseEnd.statusCode, 302)
t.matchStrict(responseEnd.cookies[0].name, 'custom-redirect-state')
t.matchStrict(responseEnd.cookies[0].value, String)

t.end()
}
)
})
})

t.test('options.verifierCookieName', (t) => {
t.plan(2)

t.test('should be a string', (t) => {
t.plan(1)

const fastify = createFastify({ logger: { level: 'silent' } })

fastify
.register(fastifyOauth2, {
name: 'the-name',
credentials: {
client: {
id: 'my-client-id',
secret: 'my-secret'
},
auth: fastifyOauth2.GITHUB_CONFIGURATION
},
callbackUri: '/callback',
verifierCookieName: 42
})
.ready((err) => {
t.strictSame(
err.message,
'options.verifierCookieName should be a string'
)
})
})

t.test('with custom cookie name', (t) => {
t.plan(4)

const fastify = createFastify({ logger: { level: 'silent' } })

fastify.register(fastifyOauth2, {
name: 'the-name',
credentials: {
client: {
id: 'my-client-id',
secret: 'my-secret'
},
auth: fastifyOauth2.GITHUB_CONFIGURATION
},
callbackUri: '/callback',
startRedirectPath: '/login',
verifierCookieName: 'custom-verifier',
pkce: 'plain'
})

t.teardown(fastify.close.bind(fastify))

fastify.inject(
{
method: 'GET',
url: '/login'
},
function (err, responseEnd) {
t.error(err)

t.equal(responseEnd.statusCode, 302)
t.matchStrict(responseEnd.cookies[1].name, 'custom-verifier')
t.matchStrict(responseEnd.cookies[1].value, String)

t.end()
}
)
})
})
2 changes: 2 additions & 0 deletions types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ declare namespace fastifyOauth2 {
userAgent?: string | false;
pkce?: 'S256' | 'plain';
discovery?: { issuer: string; }
redirectStateCookieName?: string;
verifierCookieName?: string;
}

export type TToken = 'access_token' | 'refresh_token'
Expand Down
2 changes: 2 additions & 0 deletions types/index.test-d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ const OAuth2Options: FastifyOAuth2Options = {
secure: true,
sameSite: 'none'
},
redirectStateCookieName: 'redirect-state-cookie',
verifierCookieName: 'verifier-cookie',
};

expectAssignable<FastifyOAuth2Options>({
Expand Down

0 comments on commit 3b1ab83

Please sign in to comment.