Skip to content

Commit

Permalink
Merge branch 'master' of github.com:fastify/fastify-oauth2
Browse files Browse the repository at this point in the history
  • Loading branch information
mcollina committed Oct 3, 2023
2 parents 6d6964f + e62fac6 commit 77631fe
Show file tree
Hide file tree
Showing 6 changed files with 39 additions and 21 deletions.
20 changes: 11 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -221,20 +221,20 @@ See the [`example/`](./examples/) folder for more examples.
## Reference

This Fastify plugin decorates the fastify instance with the [`simple-oauth2`](https://github.com/lelylan/simple-oauth2)
instance inside a **namespace** specified by the property `name`.
instance inside a **namespace** specified by the property `name` both with and without an `oauth2` prefix.

E.g. For `name: 'customOauth2'`, the `simple-oauth2` instance will become accessible like this:

`fastify.customOauth2.oauth2`
`fastify.oauth2CustomOauth2.oauth2` and `fastify.customOauth2.oauth2`

In this manner we are able to register multiple OAuth providers and each OAuth providers `simple-oauth2` instance will live in it's own **namespace**.

E.g.

- `fastify.facebook.oauth2`
- `fastify.github.oauth2`
- `fastify.spotify.oauth2`
- `fastify.vkontakte.oauth2`
- `fastify.oauth2Facebook.oauth2`
- `fastify.oauth2Github.oauth2`
- `fastify.oauth2Spotify.oauth2`
- `fastify.oauth2Vkontakte.oauth2`

Assuming we have registered multiple OAuth providers like this:

Expand Down Expand Up @@ -263,7 +263,7 @@ fastify.googleOAuth2.getNewAccessTokenUsingRefreshToken(currentAccessToken, (err

```js
fastify.get('/external', { /* Hooks can be used here */ }, async (req, reply) => {
const authorizationEndpoint = fastify.customOAuth2.generateAuthorizationUri(req, reply);
const authorizationEndpoint = fastify.oauth2CustomOAuth2.generateAuthorizationUri(req, reply);
reply.redirect(authorizationEndpoint)
});
```
Expand All @@ -282,8 +282,8 @@ fastify.googleOAuth2.revokeAllToken(currentAccessToken, undefined, (err) => {
```
E.g. For `name: 'customOauth2'`, the helpers `getAccessTokenFromAuthorizationCodeFlow` and `getNewAccessTokenUsingRefreshToken` will become accessible like this:

- `fastify.customOauth2.getAccessTokenFromAuthorizationCodeFlow`
- `fastify.customOauth2.getNewAccessTokenUsingRefreshToken`
- `fastify.oauth2CustomOauth2.getAccessTokenFromAuthorizationCodeFlow`
- `fastify.oauth2CustomOauth2.getNewAccessTokenUsingRefreshToken`

## Usage with TypeScript

Expand All @@ -302,6 +302,8 @@ declare module 'fastify' {
}
```

All auth configurations are made available with an `oauth2` prefix that's typed to `OAuth2Namespace | undefined`, such as eg. `fastify.oauth2CustomOauth2` for `customOauth2`.

## Provider Quirks

The following providers require additional work to be set up correctly.
Expand Down
23 changes: 13 additions & 10 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
'use strict'

const { randomBytes } = require('crypto')
const { randomBytes } = require('node:crypto')

const fp = require('fastify-plugin')
const { AuthorizationCode } = require('simple-oauth2')
const kGenerateCallbackUriParams = Symbol.for('fastify-oauth2.generate-callback-uri-params')

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

const USER_AGENT = 'fastify-oauth2'

Expand Down Expand Up @@ -206,15 +206,18 @@ function fastifyOauth2 (fastify, options, next) {
fastify.get(startRedirectPath, { schema }, startRedirectHandler)
}

const decoration = {
oauth2,
getAccessTokenFromAuthorizationCodeFlow,
getNewAccessTokenUsingRefreshToken,
generateAuthorizationUri,
revokeToken,
revokeAllToken
}

try {
fastify.decorate(name, {
oauth2,
getAccessTokenFromAuthorizationCodeFlow,
getNewAccessTokenUsingRefreshToken,
generateAuthorizationUri,
revokeToken,
revokeAllToken
})
fastify.decorate(name, decoration)
fastify.decorate(`oauth2${name.slice(0, 1).toUpperCase()}${name.slice(1)}`, decoration)
} catch (e) {
next(e)
return
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
"snazzy": "^9.0.0",
"standard": "^17.1.0",
"tap": "^16.3.8",
"tsd": "^0.28.1"
"tsd": "^0.29.0"
},
"dependencies": {
"@fastify/cookie": "^9.0.4",
Expand Down
5 changes: 4 additions & 1 deletion test/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
const t = require('tap')
const nock = require('nock')
const createFastify = require('fastify')
const crypto = require('crypto')
const crypto = require('node:crypto')
const fastifyOauth2 = require('..')

nock.disableNetConnect()
Expand Down Expand Up @@ -85,6 +85,9 @@ t.test('fastify-oauth2', t => {
})

fastify.get('/', function (request, reply) {
if (this.githubOAuth2 !== this.oauth2GithubOAuth2) {
throw new Error('Expected oauth2GithubOAuth2 to match githubOAuth2')
}
this.githubOAuth2.getAccessTokenFromAuthorizationCodeFlow(request, (err, result) => {
if (err) throw err

Expand Down
9 changes: 9 additions & 0 deletions types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -162,3 +162,12 @@ declare namespace fastifyOauth2 {
declare function fastifyOauth2(...params: Parameters<FastifyOauth2>): ReturnType<FastifyOauth2>

export = fastifyOauth2

type UpperCaseCharacters = 'A' | 'B' | 'C' | 'D' | 'E' | 'F' | 'G' | 'H' | 'I' | 'J' | 'K' | 'L' | 'M' | 'N' | 'O' | 'P' | 'Q' | 'R' | 'S' | 'T' | 'U' | 'V' | 'W' | 'X' | 'Y' | 'Z';

declare module 'fastify' {
interface FastifyInstance {
// UpperCaseCharacters ensures that the name has at least one character in it + is a simple camel-case:ification
[key: `oauth2${UpperCaseCharacters}${string}`]: fastifyOauth2.OAuth2Namespace | undefined;
}
}
1 change: 1 addition & 0 deletions types/index.test-d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ expectAssignable<ProviderConfiguration>(fastifyOauth2.YANDEX_CONFIGURATION);

server.get('/testOauth/callback', async (request, reply) => {
expectType<OAuth2Namespace>(server.testOAuthName);
expectType<OAuth2Namespace | undefined>(server.oauth2TestOAuthName);

expectType<OAuth2Token>(await server.testOAuthName.getAccessTokenFromAuthorizationCodeFlow(request));
expectType<Promise<OAuth2Token>>(server.testOAuthName.getAccessTokenFromAuthorizationCodeFlow(request));
Expand Down

0 comments on commit 77631fe

Please sign in to comment.