diff --git a/lib/build/recipe/thirdparty/providers/github.js b/lib/build/recipe/thirdparty/providers/github.js index 67aa54a08..46908eb1e 100644 --- a/lib/build/recipe/thirdparty/providers/github.js +++ b/lib/build/recipe/thirdparty/providers/github.js @@ -84,6 +84,36 @@ function Github(input) { if (input.config.tokenEndpoint === undefined) { input.config.tokenEndpoint = "https://github.com/login/oauth/access_token"; } + if (input.config.validateAccessToken === undefined) { + input.config.validateAccessToken = ({ accessToken, clientConfig }) => + __awaiter(this, void 0, void 0, function* () { + const basicAuthToken = Buffer.from( + `${clientConfig.clientId}:${ + clientConfig.clientSecret === undefined ? "" : clientConfig.clientSecret + }` + ).toString("base64"); + const applicationsResponse = yield cross_fetch_1.default( + `https://api.github.com/applications/${clientConfig.clientId}/token`, + { + headers: { + Authorization: `Basic ${basicAuthToken}`, + "Content-Type": "application/json", + }, + method: "POST", + body: JSON.stringify({ + access_token: accessToken, + }), + } + ); + if (applicationsResponse.status !== 200) { + throw new Error("Invalid access token"); + } + const body = yield applicationsResponse.json(); + if (body.app === undefined || body.app.client_id !== clientConfig.clientId) { + throw new Error("Access token does not belong to your application"); + } + }); + } const oOverride = input.override; input.override = function (originalImplementation) { const oGetConfig = originalImplementation.getConfigForClientType; @@ -98,6 +128,13 @@ function Github(input) { }; originalImplementation.getUserInfo = function (input) { return __awaiter(this, void 0, void 0, function* () { + if (originalImplementation.config.validateAccessToken !== undefined) { + yield originalImplementation.config.validateAccessToken({ + accessToken: input.oAuthTokens.access_token, + clientConfig: originalImplementation.config, + userContext: input.userContext, + }); + } const headers = { Authorization: `Bearer ${input.oAuthTokens.access_token}`, Accept: "application/vnd.github.v3+json", diff --git a/lib/ts/recipe/thirdparty/providers/github.ts b/lib/ts/recipe/thirdparty/providers/github.ts index cc733154f..5ffb8fa1f 100644 --- a/lib/ts/recipe/thirdparty/providers/github.ts +++ b/lib/ts/recipe/thirdparty/providers/github.ts @@ -58,6 +58,38 @@ export default function Github(input: ProviderInput): TypeProvider { input.config.tokenEndpoint = "https://github.com/login/oauth/access_token"; } + if (input.config.validateAccessToken === undefined) { + input.config.validateAccessToken = async ({ accessToken, clientConfig }) => { + const basicAuthToken = Buffer.from( + `${clientConfig.clientId}:${clientConfig.clientSecret === undefined ? "" : clientConfig.clientSecret}` + ).toString("base64"); + + const applicationsResponse = await fetch( + `https://api.github.com/applications/${clientConfig.clientId}/token`, + { + headers: { + Authorization: `Basic ${basicAuthToken}`, + "Content-Type": "application/json", + }, + method: "POST", + body: JSON.stringify({ + access_token: accessToken, + }), + } + ); + + if (applicationsResponse.status !== 200) { + throw new Error("Invalid access token"); + } + + const body = await applicationsResponse.json(); + + if (body.app === undefined || body.app.client_id !== clientConfig.clientId) { + throw new Error("Access token does not belong to your application"); + } + }; + } + const oOverride = input.override; input.override = function (originalImplementation) { @@ -73,6 +105,14 @@ export default function Github(input: ProviderInput): TypeProvider { }; originalImplementation.getUserInfo = async function (input) { + if (originalImplementation.config.validateAccessToken !== undefined) { + await originalImplementation.config.validateAccessToken({ + accessToken: input.oAuthTokens.access_token, + clientConfig: originalImplementation.config, + userContext: input.userContext, + }); + } + const headers = { Authorization: `Bearer ${input.oAuthTokens.access_token}`, Accept: "application/vnd.github.v3+json",