diff --git a/app/image-tools/README.md b/app/image-tools/README.md index 8aaf11c944..7b4a6a743c 100644 --- a/app/image-tools/README.md +++ b/app/image-tools/README.md @@ -13,8 +13,12 @@ A lightweight SPA + Vercel Functions app for uploading token/chain assets and op - `APP_BASE_URL` — optional; default request origin. Only set if SPA and API are on different origins. For the public deployment, leave unset or set to `https://token-assets.yearn.fi`; do not point this at a Vercel alias. - `REPO_OWNER` (default `yearn`), `REPO_NAME` (default `tokenAssets`). - - `ALLOW_REPO_OVERRIDE` — set to `true` only if you intentionally want to target a non-yearn repo when deploying from a fork. -- GitHub OAuth App callback must allow the current domain: `https:///api/auth/github/callback` (or `http://localhost:3000/...` for `vercel dev`). + - `ALLOW_REPO_OVERRIDE` — set to `true` only if you intentionally want to target a non-yearn repo when deploying + from a fork. +- GitHub OAuth App callback must be configured to the deployed API callback URL: + `https:///api/auth/github/callback`. The client intentionally does not send a `redirect_uri`; GitHub + uses the callback URL registered on the OAuth App, and the API redirects back to `APP_BASE_URL` after exchanging the + code. ## Commands diff --git a/app/image-tools/api/auth/github/callback.ts b/app/image-tools/api/auth/github/callback.ts index 8515c32d77..152e82f408 100644 --- a/app/image-tools/api/auth/github/callback.ts +++ b/app/image-tools/api/auth/github/callback.ts @@ -5,7 +5,6 @@ export default async function (req: Request): Promise { const url = new URL(req.url); const code = url.searchParams.get('code'); const state = url.searchParams.get('state') || ''; - const redirectUri = new URL('/api/auth/github/callback', url.origin).toString(); if (!code) { return new Response(JSON.stringify({error: 'Missing code'}), { status: 400, @@ -28,8 +27,7 @@ export default async function (req: Request): Promise { body: JSON.stringify({ client_id: clientId, client_secret: clientSecret, - code, - redirect_uri: redirectUri + code }) }); if (!tokenRes.ok) { diff --git a/app/image-tools/src/components/GithubSignIn.tsx b/app/image-tools/src/components/GithubSignIn.tsx index 8fd01ba64c..a93af3e5b3 100644 --- a/app/image-tools/src/components/GithubSignIn.tsx +++ b/app/image-tools/src/components/GithubSignIn.tsx @@ -6,12 +6,10 @@ import { storeAuthState, clearStoredAuth, buildAuthorizeUrl, - getGithubCallbackUrl, markAuthPending, clearAuthPending, readAuthPending } from '../lib/githubAuth'; -import {API_BASE_URL} from '../lib/api'; function randomState(len = 20) { const chars = 'abcdefghijklmnopqrstuvwxyz0123456789'; @@ -67,7 +65,7 @@ export const GithubSignIn: React.FC = ({token}) => { storeAuthState(state); markAuthPending(); setConnecting(true); - window.location.href = buildAuthorizeUrl(clientId, state, getGithubCallbackUrl(API_BASE_URL)); + window.location.href = buildAuthorizeUrl(clientId, state); }; const signOut = () => { diff --git a/app/image-tools/src/lib/githubAuth.ts b/app/image-tools/src/lib/githubAuth.ts index a537866edf..3ab7c726ab 100644 --- a/app/image-tools/src/lib/githubAuth.ts +++ b/app/image-tools/src/lib/githubAuth.ts @@ -3,16 +3,11 @@ export const AUTH_STATE_STORAGE_KEY = 'auth_state'; export const AUTH_CHANGE_EVENT = 'github-auth-changed'; export const AUTH_PENDING_STORAGE_KEY = 'github_oauth_pending'; -export function getGithubCallbackUrl(origin = window.location.origin) { - return new URL('/api/auth/github/callback', origin).toString(); -} - -export function buildAuthorizeUrl(clientId: string, state: string, redirectUri = getGithubCallbackUrl()) { +export function buildAuthorizeUrl(clientId: string, state: string) { const url = new URL('https://github.com/login/oauth/authorize'); url.searchParams.set('client_id', clientId); url.searchParams.set('state', state); url.searchParams.set('scope', 'public_repo'); - url.searchParams.set('redirect_uri', redirectUri); url.searchParams.set('prompt', 'select_account'); return url.toString(); }