From cef4be898a31854870c333433b1f64d7d6c44c73 Mon Sep 17 00:00:00 2001 From: Carlos Sanjines Aldazosa Date: Wed, 20 Mar 2024 01:37:16 -0400 Subject: [PATCH] fix(oauth-providers): OAuth Providers Github App email problem (#421) * [UPDATE (OAuth Providers): Github] request emails if Github App * changlog * [FIX: changeset] minor bump instead patch bump --- .changeset/sixty-ladybugs-travel.md | 5 +++ .../src/providers/github/authFlow.ts | 33 +++++++++++++++++-- .../src/providers/github/types.ts | 7 ++++ packages/oauth-providers/test/handlers.ts | 17 +++++++++- 4 files changed, 59 insertions(+), 3 deletions(-) create mode 100644 .changeset/sixty-ladybugs-travel.md diff --git a/.changeset/sixty-ladybugs-travel.md b/.changeset/sixty-ladybugs-travel.md new file mode 100644 index 00000000..38ed57be --- /dev/null +++ b/.changeset/sixty-ladybugs-travel.md @@ -0,0 +1,5 @@ +--- +'@hono/oauth-providers': patch +--- + +Github App user email problem diff --git a/packages/oauth-providers/src/providers/github/authFlow.ts b/packages/oauth-providers/src/providers/github/authFlow.ts index 12e96cfc..1b15b495 100644 --- a/packages/oauth-providers/src/providers/github/authFlow.ts +++ b/packages/oauth-providers/src/providers/github/authFlow.ts @@ -1,7 +1,13 @@ import { HTTPException } from 'hono/http-exception' import { toQueryParams } from '../../utils/objectToQuery' -import type { GitHubErrorResponse, GitHubTokenResponse, GitHubUser, GitHubScope } from './types' +import type { + GitHubErrorResponse, + GitHubTokenResponse, + GitHubUser, + GitHubScope, + GitHubEmailResponse, +} from './types' type GithubAuthFlow = { client_id: string @@ -15,6 +21,9 @@ type Token = { token: string expires_in?: number } + +const userAgent = 'Hono-Auth-App' + export class AuthFlow { client_id: string client_secret: string @@ -95,7 +104,7 @@ export class AuthFlow { Authorization: `Bearer ${this.token?.token}`, Accept: 'application/json', 'Content-Type': 'application/json', - 'User-Agent': 'Hono-Auth-App', + 'User-Agent': userAgent, }, }).then((res) => res.json())) as GitHubUser | GitHubErrorResponse @@ -103,6 +112,26 @@ export class AuthFlow { throw new HTTPException(400, { message: response.message }) } + if (!this.oauthApp) { + const emails = (await fetch('https://api.github.com/user/emails', { + headers: { + Authorization: `Bearer ${this.token?.token}`, + 'User-Agent': userAgent, + }, + }).then((res) => res.json())) as GitHubEmailResponse[] | GitHubErrorResponse + + if ('message' in emails) { + throw new HTTPException(400, { message: emails.message }) + } + + let email = emails.find((emails) => emails.primary === true)?.email + if (email === undefined) { + email = emails.find((emails) => !emails.email.includes('@users.noreply.github.com'))?.email + } + + response.email = email as string + } + if ('id' in response) { this.user = response } diff --git a/packages/oauth-providers/src/providers/github/types.ts b/packages/oauth-providers/src/providers/github/types.ts index a72fe28d..009b38ae 100644 --- a/packages/oauth-providers/src/providers/github/types.ts +++ b/packages/oauth-providers/src/providers/github/types.ts @@ -95,3 +95,10 @@ export type GitHubUser = { private_repos: number } } + +export type GitHubEmailResponse = { + email: string + primary: boolean + vrified: boolean + visibility: string +} diff --git a/packages/oauth-providers/test/handlers.ts b/packages/oauth-providers/test/handlers.ts index 5ebdd06b..40e69bb1 100644 --- a/packages/oauth-providers/test/handlers.ts +++ b/packages/oauth-providers/test/handlers.ts @@ -81,6 +81,7 @@ export const handlers = [ } ), http.get('https://api.github.com/user', () => HttpResponse.json(githubUser)), + http.get('https://api.github.com/user/emails', () => HttpResponse.json(githubEmails)), // LinkedIn http.post( 'https://www.linkedin.com/oauth/v2/accessToken', @@ -265,7 +266,7 @@ export const githubUser = { company: '@rvesoftware', blog: 'https://monoald.github.io/', location: 'Knowhere', - email: null, + email: 'test@email.com', hireable: null, bio: 'BIO description', twitter_username: 'monoald', @@ -288,6 +289,20 @@ export const githubUser = { private_repos: 10000, }, } +export const githubEmails = [ + { + email: 'test@email.com', + primary: true, + verified: true, + visibility: 'public', + }, + { + email: '671450+test@users.noreply.github.com', + primary: false, + verified: true, + visibility: null, + }, +] export const githubCodeError = { error_description: 'Invalid Code.', }