From 90411e29dff6c1447edf69894df68c8b8bd47904 Mon Sep 17 00:00:00 2001 From: Konstantin Wohlwend Date: Mon, 8 Sep 2025 22:17:33 -0700 Subject: [PATCH 1/2] Better OAuth error logging --- .../[user_id]/[provider_id]/access-token/crud.tsx | 4 ++-- apps/backend/src/oauth/providers/github.tsx | 2 ++ packages/stack-shared/src/utils/jwt.tsx | 12 ++++++++++++ 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/apps/backend/src/app/api/latest/connected-accounts/[user_id]/[provider_id]/access-token/crud.tsx b/apps/backend/src/app/api/latest/connected-accounts/[user_id]/[provider_id]/access-token/crud.tsx index 824ccdda6..093a52a0d 100644 --- a/apps/backend/src/app/api/latest/connected-accounts/[user_id]/[provider_id]/access-token/crud.tsx +++ b/apps/backend/src/app/api/latest/connected-accounts/[user_id]/[provider_id]/access-token/crud.tsx @@ -111,14 +111,14 @@ export const connectedAccountAccessTokenCrudHandlers = createLazyProxy(() => cre scope: data.scope, }); } catch (error) { - captureError('oauth-access-token-refresh-error', { + captureError('oauth-access-token-refresh-error', new StackAssertionError('Error refreshing access token — this might be nothing bad and the refresh token might just be expired, but we should instead of throwing an error check whether this is a legit error or not', { error, tenancyId: auth.tenancy.id, providerId: params.provider_id, userId: params.user_id, refreshToken: token.refreshToken, scope: data.scope, - }); + })); // mark the token as invalid await prisma.oAuthToken.update({ diff --git a/apps/backend/src/oauth/providers/github.tsx b/apps/backend/src/oauth/providers/github.tsx index 23b7ab980..260109bac 100644 --- a/apps/backend/src/oauth/providers/github.tsx +++ b/apps/backend/src/oauth/providers/github.tsx @@ -1,5 +1,6 @@ import { getEnvVariable } from "@stackframe/stack-shared/dist/utils/env"; import { StackAssertionError, StatusError } from "@stackframe/stack-shared/dist/utils/errors"; +import { getJwtInfo } from "@stackframe/stack-shared/dist/utils/jwt"; import { OAuthUserInfo, validateUserInfo } from "../utils"; import { OAuthBaseProvider, TokenSet } from "./base"; @@ -42,6 +43,7 @@ export class GithubProvider extends OAuthBaseProvider { hasAccessToken: !!tokenSet.accessToken, hasRefreshToken: !!tokenSet.refreshToken, accessTokenExpiredAt: tokenSet.accessTokenExpiredAt, + jwtInfo: await getJwtInfo({ jwt: tokenSet.accessToken }), }); } const rawUserInfo = await rawUserInfoRes.json(); diff --git a/packages/stack-shared/src/utils/jwt.tsx b/packages/stack-shared/src/utils/jwt.tsx index 08c701c98..0939a0056 100644 --- a/packages/stack-shared/src/utils/jwt.tsx +++ b/packages/stack-shared/src/utils/jwt.tsx @@ -7,6 +7,7 @@ import { getEnvVariable } from "./env"; import { StackAssertionError } from "./errors"; import { globalVar } from "./globals"; import { pick } from "./objects"; +import { Result } from "./results"; function getStackServerSecret() { const STACK_SERVER_SECRET = getEnvVariable("STACK_SERVER_SECRET"); @@ -18,6 +19,17 @@ function getStackServerSecret() { return STACK_SERVER_SECRET; } +export async function getJwtInfo(options: { + jwt: string, +}) { + try { + const decodedJwt = jose.decodeJwt(options.jwt); + return Result.ok({ payload: decodedJwt }); + } catch (e) { + return Result.error(e); + } +} + export async function signJWT(options: { issuer: string, audience: string, From 389fdefe5570968ac92f8abe85adac85cd085d5c Mon Sep 17 00:00:00 2001 From: Konstantin Wohlwend Date: Mon, 8 Sep 2025 22:18:35 -0700 Subject: [PATCH 2/2] Fix weird formatting --- packages/init-stack/src/index.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/packages/init-stack/src/index.ts b/packages/init-stack/src/index.ts index 0ef306fb1..11059a178 100644 --- a/packages/init-stack/src/index.ts +++ b/packages/init-stack/src/index.ts @@ -247,9 +247,6 @@ async function main(): Promise { shell: true, cwd: projectPath, }); - shell: true, - cwd: projectPath, - }); await capture(`dependencies-installed`, { packageManager,