Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 61 additions & 8 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<OAuth2Token>;

/** Revoke access or refresh token */
revoke(tokenType: 'access_token' | 'refresh_token'): Promise<void>;

/** Revoke both the existing access and refresh tokens */
revokeAll(): Promise<void>;
}

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 {
Expand All @@ -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<OAuth2Token>;
getNewAccessTokenUsingRefreshToken(refreshToken: Token, params: Object): Promise<OAuth2Token>;

generateAuthorizationUri(
request: FastifyRequest,
Expand Down
10 changes: 5 additions & 5 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
}

Expand All @@ -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)
Expand Down Expand Up @@ -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)
Expand All @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
},
"dependencies": {
"fastify-plugin": "^4.0.0",
"simple-oauth2": "^3.4.0"
"simple-oauth2": "^4.3.0"
},
"tsd": {
"directory": "test/types"
Expand Down
4 changes: 2 additions & 2 deletions test/plugin.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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 {
Expand Down
18 changes: 9 additions & 9 deletions test/types/index.test-d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down Expand Up @@ -77,35 +77,35 @@ server.get('/testOauth/callback', async request => {
expectError<void>(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<OAuth2Token>(
await server.testOAuthName.getNewAccessTokenUsingRefreshToken(token.refresh_token, {}),
await server.testOAuthName.getNewAccessTokenUsingRefreshToken(token.token, {}),
);
expectType<Promise<OAuth2Token>>(
server.testOAuthName.getNewAccessTokenUsingRefreshToken(token.refresh_token, {}),
server.testOAuthName.getNewAccessTokenUsingRefreshToken(token.token, {}),
);
expectType<void>(
server.testOAuthName.getNewAccessTokenUsingRefreshToken(
token.refresh_token,
token.token,
{},
(err: any, t: OAuth2Token): void => { },
),
);

expectError<void>(await server.testOAuthName.getNewAccessTokenUsingRefreshToken(token.refresh_token, {})); // error because Promise should not return void
expectError<void>(await server.testOAuthName.getNewAccessTokenUsingRefreshToken(token.token, {})); // error because Promise should not return void
expectError<OAuth2Token>(
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<void>(server.testOAuthName.getNewAccessTokenUsingRefreshToken(token.refresh_token, {})); // error because function call does not pass a callback as second argument.
expectError<void>(server.testOAuthName.getNewAccessTokenUsingRefreshToken(token.token, {})); // error because function call does not pass a callback as second argument.
}

expectType<string>(server.testOAuthName.generateAuthorizationUri(request));

return {
access_token: token.access_token,
access_token: token.token.access_token,
};
});