Skip to content

Commit

Permalink
fastify-session integration (#421)
Browse files Browse the repository at this point in the history
* chore: added support for fastify/session

* chore: docs update, interface for session manager

* chore: fix test attempt

* chore: added package-lock.json

* chore: reusable test suite added

* chore: package-lock update

* chore: improved logging

* chore: minor readme update

* chore: improve tests

* chore: delete package lock

* chore: package-lock added again

* chore: fix tests

* chore: fix tests and package lock
  • Loading branch information
sameer-coder authored Jan 4, 2022
1 parent 9cb6538 commit c572f81
Show file tree
Hide file tree
Showing 16 changed files with 1,681 additions and 1,466 deletions.
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,6 @@ dist
.DS_Store

# lock files
package-lock.json
yarn.lock

# editor files
Expand Down
26 changes: 26 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,32 @@ server.post(
server.listen(0)
```

Alternatively, [`@fastify/session`](https://github.com/fastify/session) is also supported and works out of the box for session storage.
Here's an example:

```js
import { Authenticator } from 'fastify-passport'
import fastifyCookie from 'fastify-cookie'
import fastifySession from '@fastify/session'

const server = fastify()

// setup an Authenticator instance which uses @fastify/session
const fastifyPassport = new Authenticator()

server.register(fastifyCookie)
server.register(fastifySession, { secret: 'secret with minimum length of 32 characters' })

// initialize fastify-passport
server.register(fastifyPassport.initialize())

// register an example strategy for fastifyPassport to authenticate users using
fastifyPassport.use('test', new SomePassportStrategy()) // you'd probably use some passport strategy from npm here
```

## Difference between `fastify-secure-session` and `@fastify/session`
`fastify-secure-session` and `@fastify/session` are both session plugins for Fastify which are capable of encrypting/decrypting the session. The main difference is that `fastify-secure-session` uses the stateless approach and stores the whole session in an encrypted cookie whereas `@fastify/session` uses the stateful approach for sessions and stores them in a session store.

## Session Serialization

In a typical web application, the credentials used to authenticate a user will only be transmitted once when a user logs in, and after, they are considered logged in because of some data stored in their session. `fastify-passport` implements this pattern by storing sessions using `fastify-secure-cookie`, and serializing/deserializing user objects to and from the session referenced by the cookie. `fastify-passport` cannot store rich object classes in the session, only JSON objects, so you must register a serializer / deserializer pair if you want to say fetch a User object from your database, and store only a user ID in the session.
Expand Down
62 changes: 62 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,18 +47,19 @@
"fastify": "^3.0.3"
},
"devDependencies": {
"@fastify/session": "^6.3.0",
"@types/jest": "^27.0.0",
"@types/node": "^17.0.0",
"@types/passport": "^1.0.5",
"@types/semver": "^7.3.4",
"@types/set-cookie-parser": "^2.4.0",
"@typescript-eslint/eslint-plugin": "^5.8.1",
"@typescript-eslint/parser": "^5.8.1",
"eslint": "^8.5.0",
"eslint-config-prettier": "^8.1.0",
"eslint-plugin-prettier": "^4.0.0",
"eslint": "^8.5.0",
"fastify-secure-session": "^3.0.0",
"fastify": "^3.9.2",
"fastify-secure-session": "^3.0.0",
"got": "^11.8.1",
"jest": "^27.0.6",
"passport-facebook": "^3.0.0",
Expand Down
2 changes: 1 addition & 1 deletion src/AuthenticationRoute.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ type FailureObject = {
}

const addMessage = (request: FastifyRequest, message: string) => {
const existing = request.session.get('messages')
const existing: any = request.session.get('messages')
const messages = existing ? [...existing, message] : [message]
request.session.set('messages', messages)
}
Expand Down
2 changes: 1 addition & 1 deletion src/session-managers/SecureSessionManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import { FastifyRequest } from 'fastify'
import { SerializeFunction } from '../Authenticator'

/** Class for storing passport data in the session using `fastify-secure-session` */
/** Class for storing passport data in the session using `fastify-secure-session` or `@fastify/session` */
export class SecureSessionManager {
key: string
serializeUser: SerializeFunction
Expand Down
37 changes: 22 additions & 15 deletions test/authorize.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,29 @@ export class TestThirdPartyStrategy extends Strategy {
}
}

describe('.authorize', () => {
test(`should return 401 Unauthorized if not logged in`, async () => {
const { server, fastifyPassport } = getConfiguredTestServer()
fastifyPassport.use(new TestThirdPartyStrategy('third-party'))
const suite = (sessionPluginName) => {
describe(`${sessionPluginName} tests`, () => {
describe('.authorize', () => {
test(`should return 401 Unauthorized if not logged in`, async () => {
const { server, fastifyPassport } = getConfiguredTestServer()
fastifyPassport.use(new TestThirdPartyStrategy('third-party'))

server.get('/', { preValidation: fastifyPassport.authorize('third-party') }, async (request) => {
const user = request.user as any
expect(user).toBeFalsy()
const account = request.account as any
expect(account.id).toBeTruthy()
expect(account.name).toEqual('test')
server.get('/', { preValidation: fastifyPassport.authorize('third-party') }, async (request) => {
const user = request.user as any
expect(user).toBeFalsy()
const account = request.account as any
expect(account.id).toBeTruthy()
expect(account.name).toEqual('test')

return 'it worked'
})
return 'it worked'
})

const response = await server.inject({ method: 'GET', url: '/' })
expect(response.statusCode).toEqual(200)
const response = await server.inject({ method: 'GET', url: '/' })
expect(response.statusCode).toEqual(200)
})
})
})
})
}

suite('@fastify/session')
suite('fastify-secure-session')
Loading

0 comments on commit c572f81

Please sign in to comment.