diff --git a/index.d.ts b/index.d.ts index c2a810b..b892da6 100644 --- a/index.d.ts +++ b/index.d.ts @@ -31,26 +31,79 @@ export interface FastifyOAuth2Options { schema?: object; } -export interface OAuth2Token { +export interface Token { token_type: 'bearer'; access_token: string; refresh_token?: string; expires_in: number; + expires_at: Date; +} + +export interface OAuth2Token { + /** + * Immutable object containing the token object provided while constructing a new access token instance. + * This property will usually have the schema as specified by RFC6750, + * but the exact properties may vary between authorization servers. + */ + token: Token; + + /** + * Determines if the current access token is definitely expired or not + * @param expirationWindowSeconds Window of time before the actual expiration to refresh the token. Defaults to 0. + */ + expired(expirationWindowSeconds?: number): boolean; + + /** Refresh the access token */ + refresh(params?: {}): Promise; + + /** Revoke access or refresh token */ + revoke(tokenType: 'access_token' | 'refresh_token'): Promise; + + /** Revoke both the existing access and refresh tokens */ + revokeAll(): Promise; } export interface ProviderConfiguration { - authorizeHost: string; - authorizePath: string; + /** String used to set the host to request the tokens to. Required. */ tokenHost: string; - tokenPath: string; + /** String path to request an access token. Default to /oauth/token. */ + tokenPath?: string | undefined; + /** String path to revoke an access token. Default to /oauth/revoke. */ + revokePath?: string | undefined; + /** String used to set the host to request an "authorization code". Default to the value set on auth.tokenHost. */ + authorizeHost?: string | undefined; + /** String path to request an authorization code. Default to /oauth/authorize. */ + authorizePath?: string | undefined; } export interface Credentials { client: { - id: string; - secret: string; + /** Service registered client id. Required. */ + id: string; + /** Service registered client secret. Required. */ + secret: string; + /** Parameter name used to send the client secret. Default to client_secret. */ + secretParamName?: string | undefined; + /** Parameter name used to send the client id. Default to client_id. */ + idParamName?: string | undefined; }; auth: ProviderConfiguration; + /** + * Used to set global options to the internal http library (wreck). + * All options except baseUrl are allowed + * Defaults to header.Accept = "application/json" + */ + http?: {} | undefined; + options?: { + /** Format of data sent in the request body. Defaults to form. */ + bodyFormat?: "json" | "form" | undefined; + /** + * Indicates the method used to send the client.id/client.secret authorization params at the token request. + * If set to body, the bodyFormat option will be used to format the credentials. + * Defaults to header + */ + authorizationMethod?: "header" | "body" | undefined; + } | undefined; } export interface OAuth2Namespace { @@ -64,12 +117,12 @@ export interface OAuth2Namespace { ): void; getNewAccessTokenUsingRefreshToken( - refreshToken: string, + refreshToken: Token, params: Object, callback: (err: any, token: OAuth2Token) => void, ): void; - getNewAccessTokenUsingRefreshToken(refreshToken: string, params: Object): Promise; + getNewAccessTokenUsingRefreshToken(refreshToken: Token, params: Object): Promise; generateAuthorizationUri( request: FastifyRequest, diff --git a/index.js b/index.js index 4cc4bf6..27d9774 100644 --- a/index.js +++ b/index.js @@ -3,7 +3,7 @@ const defaultState = require('crypto').randomBytes(10).toString('hex') const fp = require('fastify-plugin') -const oauth2Module = require('simple-oauth2') +const { AuthorizationCode } = require('simple-oauth2') const kGenerateCallbackUriParams = Symbol.for('fastify-oauth2.generate-callback-uri-params') const promisify = require('util').promisify @@ -77,7 +77,7 @@ const oauthPlugin = fp(function (fastify, options, next) { state }) - const authorizationUri = oauth2.authorizationCode.authorizeURL(urlOptions) + const authorizationUri = oauth2.authorizeURL(urlOptions) return authorizationUri } @@ -88,7 +88,7 @@ const oauthPlugin = fp(function (fastify, options, next) { } const cbk = function (o, code, callback) { - return callbackify(o.oauth2.authorizationCode.getToken.bind(o.oauth2.authorizationCode, { + return callbackify(o.oauth2.getToken.bind(o.oauth2, { code, redirect_uri: callbackUri }))(callback) @@ -116,7 +116,7 @@ const oauthPlugin = fp(function (fastify, options, next) { } function getNewAccessTokenUsingRefreshTokenCallbacked (refreshToken, params, callback) { - const accessToken = fastify[name].oauth2.accessToken.create({ refresh_token: refreshToken }) + const accessToken = fastify[name].oauth2.createToken(refreshToken) callbackify(accessToken.refresh.bind(accessToken, params))(callback) } const getNewAccessTokenUsingRefreshTokenPromisified = promisify(getNewAccessTokenUsingRefreshTokenCallbacked) @@ -127,7 +127,7 @@ const oauthPlugin = fp(function (fastify, options, next) { } getNewAccessTokenUsingRefreshTokenCallbacked(refreshToken, params, callback) } - const oauth2 = oauth2Module.create(credentials) + const oauth2 = new AuthorizationCode(credentials) if (startRedirectPath) { fastify.get(startRedirectPath, { schema }, startRedirectHandler) diff --git a/package.json b/package.json index f0e2d62..34a0dfb 100644 --- a/package.json +++ b/package.json @@ -39,7 +39,7 @@ }, "dependencies": { "fastify-plugin": "^4.0.0", - "simple-oauth2": "^3.4.0" + "simple-oauth2": "^4.3.0" }, "tsd": { "directory": "test/types" diff --git a/test/plugin.test.js b/test/plugin.test.js index 10226b2..8000414 100644 --- a/test/plugin.test.js +++ b/test/plugin.test.js @@ -92,7 +92,7 @@ t.test('fastify-oauth2', t => { if (err) throw err // attempts to refresh the token - this.githubOAuth2.getNewAccessTokenUsingRefreshToken(result.refresh_token, undefined, (err, result) => { + this.githubOAuth2.getNewAccessTokenUsingRefreshToken(result.token, undefined, (err, result) => { if (err) throw err const newToken = result @@ -133,7 +133,7 @@ t.test('fastify-oauth2', t => { return this.githubOAuth2.getAccessTokenFromAuthorizationCodeFlow(request) .then(result => { // attempts to refresh the token - return this.githubOAuth2.getNewAccessTokenUsingRefreshToken(result.refresh_token) + return this.githubOAuth2.getNewAccessTokenUsingRefreshToken(result.token) }) .then(token => { return { diff --git a/test/types/index.test-d.ts b/test/types/index.test-d.ts index 98c5c1e..ce078d7 100644 --- a/test/types/index.test-d.ts +++ b/test/types/index.test-d.ts @@ -8,7 +8,7 @@ import fastifyOauth2, { Credentials, OAuth2Namespace, OAuth2Token, ProviderConfi const auth = fastifyOauth2.GOOGLE_CONFIGURATION; const scope = ['r_emailaddress', 'r_basicprofile']; const tags = ['oauth2', 'oauth']; -const credentials = { +const credentials: Credentials = { client: { id: 'test_id', secret: 'test_secret', @@ -77,35 +77,35 @@ server.get('/testOauth/callback', async request => { expectError(server.testOAuthName.getAccessTokenFromAuthorizationCodeFlow(request)); // error because function call does not pass a callback as second argument. const token = await server.testOAuthName.getAccessTokenFromAuthorizationCodeFlow(request); - if (token.refresh_token) { + if (token.token.refresh_token) { expectType( - await server.testOAuthName.getNewAccessTokenUsingRefreshToken(token.refresh_token, {}), + await server.testOAuthName.getNewAccessTokenUsingRefreshToken(token.token, {}), ); expectType>( - server.testOAuthName.getNewAccessTokenUsingRefreshToken(token.refresh_token, {}), + server.testOAuthName.getNewAccessTokenUsingRefreshToken(token.token, {}), ); expectType( server.testOAuthName.getNewAccessTokenUsingRefreshToken( - token.refresh_token, + token.token, {}, (err: any, t: OAuth2Token): void => { }, ), ); - expectError(await server.testOAuthName.getNewAccessTokenUsingRefreshToken(token.refresh_token, {})); // error because Promise should not return void + expectError(await server.testOAuthName.getNewAccessTokenUsingRefreshToken(token.token, {})); // error because Promise should not return void expectError( server.testOAuthName.getNewAccessTokenUsingRefreshToken( - token.refresh_token, + token.token, {}, (err: any, t: OAuth2Token): void => { }, ), ); // error because non-Promise function call should return void and have a callback argument - expectError(server.testOAuthName.getNewAccessTokenUsingRefreshToken(token.refresh_token, {})); // error because function call does not pass a callback as second argument. + expectError(server.testOAuthName.getNewAccessTokenUsingRefreshToken(token.token, {})); // error because function call does not pass a callback as second argument. } expectType(server.testOAuthName.generateAuthorizationUri(request)); return { - access_token: token.access_token, + access_token: token.token.access_token, }; });