diff --git a/packages/connector-github/package.json b/packages/connector-github/package.json index 61cfbbb7f..4959167ff 100644 --- a/packages/connector-github/package.json +++ b/packages/connector-github/package.json @@ -29,6 +29,7 @@ "@logto/schemas": "^0.1.0", "@silverhand/essentials": "^1.1.0", "got": "^11.8.2", + "query-string": "^7.0.1", "zod": "^3.14.3" }, "devDependencies": { diff --git a/packages/connector-github/src/index.test.ts b/packages/connector-github/src/index.test.ts index 27731c3ea..90fd0ee83 100644 --- a/packages/connector-github/src/index.test.ts +++ b/packages/connector-github/src/index.test.ts @@ -1,5 +1,6 @@ import { ConnectorError, ConnectorErrorCodes, GetConnectorConfig } from '@logto/connector-types'; import nock from 'nock'; +import * as qs from 'query-string'; import GithubConnector from '.'; import { accessTokenEndpoint, authorizationEndpoint, userInfoEndpoint } from './constant'; @@ -37,11 +38,16 @@ describe('getAccessToken', () => { }); it('should get an accessToken by exchanging with code', async () => { - nock(accessTokenEndpoint).post('').reply(200, { - access_token: 'access_token', - scope: 'scope', - token_type: 'token_type', - }); + nock(accessTokenEndpoint) + .post('') + .reply( + 200, + qs.stringify({ + access_token: 'access_token', + scope: 'scope', + token_type: 'token_type', + }) + ); const { accessToken } = await githubMethods.getAccessToken('code'); expect(accessToken).toEqual('access_token'); }); @@ -49,7 +55,7 @@ describe('getAccessToken', () => { it('throws SocialAuthCodeInvalid error if accessToken not found in response', async () => { nock(accessTokenEndpoint) .post('') - .reply(200, { access_token: '', scope: 'scope', token_type: 'token_type' }); + .reply(200, qs.stringify({ access_token: '', scope: 'scope', token_type: 'token_type' })); await expect(githubMethods.getAccessToken('code')).rejects.toMatchError( new ConnectorError(ConnectorErrorCodes.SocialAuthCodeInvalid) ); @@ -78,11 +84,16 @@ describe('validateConfig', () => { describe('getUserInfo', () => { beforeEach(() => { - nock(accessTokenEndpoint).post('').reply(200, { - access_token: 'access_token', - scope: 'scope', - token_type: 'token_type', - }); + nock(accessTokenEndpoint) + .post('') + .reply( + 200, + qs.stringify({ + access_token: 'access_token', + scope: 'scope', + token_type: 'token_type', + }) + ); }); afterEach(() => { diff --git a/packages/connector-github/src/index.ts b/packages/connector-github/src/index.ts index 14c4e6f44..ded56a47c 100644 --- a/packages/connector-github/src/index.ts +++ b/packages/connector-github/src/index.ts @@ -11,6 +11,7 @@ import { } from '@logto/connector-types'; import { assert, conditional } from '@silverhand/essentials'; import got, { RequestError as GotRequestError } from 'got'; +import * as qs from 'query-string'; import { authorizationEndpoint, @@ -68,7 +69,7 @@ export default class GithubConnector implements SocialConnector { timeout: defaultTimeout, }); - const result = accessTokenResponseGuard.safeParse(JSON.parse(httpResponse.body)); + const result = accessTokenResponseGuard.safeParse(qs.parse(httpResponse.body)); if (!result.success) { throw new ConnectorError(ConnectorErrorCodes.InvalidResponse, result.error.message); @@ -98,6 +99,7 @@ export default class GithubConnector implements SocialConnector { if (!result.success) { throw new ConnectorError(ConnectorErrorCodes.InvalidResponse, result.error.message); } + const { id, avatar_url: avatar, email, name } = result.data; return { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1dae51eaf..273a3a59e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -333,6 +333,7 @@ importers: lint-staged: ^13.0.0 nock: ^13.2.2 prettier: ^2.3.2 + query-string: ^7.0.1 ts-jest: ^27.1.1 tsc-watch: ^5.0.0 typescript: ^4.6.2 @@ -344,6 +345,7 @@ importers: '@silverhand/essentials': 1.1.7 '@silverhand/jest-config': 0.14.0_tgc6da2oqazvrn56dzwolsqo5i got: 11.8.3 + query-string: 7.0.1 zod: 3.14.3 devDependencies: '@jest/types': 27.5.1