Call logout OAuth handler in OAuthAdapter
Signed-off-by: Alessandro Dalfovo <dalfovo.alessandro@gmail.com>
This commit is contained in:
committed by
Francesco Saltori
parent
c3e68fe249
commit
7289b5ec4e
@@ -17,7 +17,7 @@
|
||||
import express from 'express';
|
||||
import { THOUSAND_DAYS_MS, TEN_MINUTES_MS, OAuthAdapter } from './OAuthAdapter';
|
||||
import { encodeState } from './helpers';
|
||||
import { OAuthHandlers, OAuthState } from './types';
|
||||
import { OAuthHandlers, OAuthLogoutRequest, OAuthState } from './types';
|
||||
import { CookieConfigurer } from '../../providers/types';
|
||||
|
||||
const mockResponseData = {
|
||||
@@ -60,6 +60,7 @@ describe('OAuthAdapter', () => {
|
||||
refreshToken: 'token',
|
||||
};
|
||||
}
|
||||
async logout(_: OAuthLogoutRequest) {}
|
||||
}
|
||||
const providerInstance = new MyAuthProvider();
|
||||
const mockCookieConfig: ReturnType<CookieConfigurer> = {
|
||||
@@ -262,13 +263,17 @@ describe('OAuthAdapter', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('removes refresh cookie when logging out', async () => {
|
||||
it('removes refresh cookie and calls logout handler when logging out', async () => {
|
||||
const logoutSpy = jest.spyOn(providerInstance, 'logout');
|
||||
const oauthProvider = new OAuthAdapter(providerInstance, {
|
||||
...oAuthProviderOptions,
|
||||
isOriginAllowed: () => false,
|
||||
});
|
||||
|
||||
const mockRequest = {
|
||||
cookies: {
|
||||
'test-provider-refresh-token': 'token',
|
||||
},
|
||||
header: () => 'XMLHttpRequest',
|
||||
get: jest.fn(),
|
||||
} as unknown as express.Request;
|
||||
@@ -281,6 +286,7 @@ describe('OAuthAdapter', () => {
|
||||
|
||||
await oauthProvider.logout(mockRequest, mockResponse);
|
||||
expect(mockRequest.get).toHaveBeenCalledTimes(1);
|
||||
expect(logoutSpy).toHaveBeenCalledTimes(1);
|
||||
expect(mockResponse.cookie).toHaveBeenCalledTimes(1);
|
||||
expect(mockResponse.cookie).toHaveBeenCalledWith(
|
||||
expect.stringContaining('test-provider-refresh-token'),
|
||||
|
||||
@@ -39,6 +39,7 @@ import {
|
||||
OAuthStartRequest,
|
||||
OAuthRefreshRequest,
|
||||
OAuthState,
|
||||
OAuthLogoutRequest,
|
||||
} from './types';
|
||||
import { prepareBackstageIdentityResponse } from '../../providers/prepareBackstageIdentityResponse';
|
||||
|
||||
@@ -190,6 +191,14 @@ export class OAuthAdapter implements AuthProviderRouteHandlers {
|
||||
throw new AuthenticationError('Invalid X-Requested-With header');
|
||||
}
|
||||
|
||||
if (this.handlers.logout) {
|
||||
const refreshToken = this.getRefreshTokenFromCookie(req);
|
||||
const revokeRequest: OAuthLogoutRequest = Object.assign(req, {
|
||||
refreshToken,
|
||||
});
|
||||
await this.handlers.logout(revokeRequest);
|
||||
}
|
||||
|
||||
// remove refresh token cookie if it is set
|
||||
const origin = req.get('origin');
|
||||
const cookieConfig = this.getCookieConfig(origin);
|
||||
@@ -210,8 +219,7 @@ export class OAuthAdapter implements AuthProviderRouteHandlers {
|
||||
}
|
||||
|
||||
try {
|
||||
const refreshToken =
|
||||
req.cookies[`${this.options.providerId}-refresh-token`];
|
||||
const refreshToken = this.getRefreshTokenFromCookie(req);
|
||||
|
||||
// throw error if refresh token is missing in the request
|
||||
if (!refreshToken) {
|
||||
@@ -286,6 +294,10 @@ export class OAuthAdapter implements AuthProviderRouteHandlers {
|
||||
});
|
||||
};
|
||||
|
||||
private getRefreshTokenFromCookie = (req: express.Request) => {
|
||||
return req.cookies[`${this.options.providerId}-refresh-token`];
|
||||
};
|
||||
|
||||
private getGrantedScopeFromCookie = (req: express.Request) => {
|
||||
return req.cookies[`${this.options.providerId}-granted-scope`];
|
||||
};
|
||||
|
||||
@@ -26,5 +26,6 @@ export type {
|
||||
OAuthState,
|
||||
OAuthStartRequest,
|
||||
OAuthRefreshRequest,
|
||||
OAuthLogoutRequest,
|
||||
OAuthResult,
|
||||
} from './types';
|
||||
|
||||
@@ -104,6 +104,11 @@ export type OAuthRefreshRequest = express.Request<{}> & {
|
||||
refreshToken: string;
|
||||
};
|
||||
|
||||
/** @public */
|
||||
export type OAuthLogoutRequest = express.Request<{}> & {
|
||||
refreshToken: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* Any OAuth provider needs to implement this interface which has provider specific
|
||||
* handlers for different methods to perform authentication, get access tokens,
|
||||
@@ -136,5 +141,5 @@ export interface OAuthHandlers {
|
||||
/**
|
||||
* (Optional) Sign out of the auth provider.
|
||||
*/
|
||||
logout?(): Promise<void>;
|
||||
logout?(req: OAuthLogoutRequest): Promise<void>;
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
import express from 'express';
|
||||
import passport from 'passport';
|
||||
import { OAuth2Client } from 'google-auth-library';
|
||||
import { Strategy as GoogleStrategy } from 'passport-google-oauth20';
|
||||
import {
|
||||
encodeState,
|
||||
@@ -27,6 +28,7 @@ import {
|
||||
OAuthResponse,
|
||||
OAuthResult,
|
||||
OAuthStartRequest,
|
||||
OAuthLogoutRequest,
|
||||
} from '../../lib/oauth';
|
||||
import {
|
||||
executeFetchUserProfileStrategy,
|
||||
@@ -119,6 +121,11 @@ export class GoogleAuthProvider implements OAuthHandlers {
|
||||
};
|
||||
}
|
||||
|
||||
async logout(req: OAuthLogoutRequest) {
|
||||
const oauthClient = new OAuth2Client();
|
||||
await oauthClient.revokeToken(req.refreshToken);
|
||||
}
|
||||
|
||||
async refresh(req: OAuthRefreshRequest) {
|
||||
const { accessToken, refreshToken, params } =
|
||||
await executeRefreshTokenStrategy(
|
||||
|
||||
Reference in New Issue
Block a user