diff --git a/apps/studio/lib/api/apiAuthenticate.test.ts b/apps/studio/lib/api/apiAuthenticate.test.ts index e11fac9a09c..5ca46676640 100644 --- a/apps/studio/lib/api/apiAuthenticate.test.ts +++ b/apps/studio/lib/api/apiAuthenticate.test.ts @@ -3,9 +3,9 @@ import { apiAuthenticate } from './apiAuthenticate' const mocks = vi.hoisted(() => { return { - getAuthUser: vi.fn().mockResolvedValue({ - user: { - id: 'test-gotrue-id', + getUserClaims: vi.fn().mockResolvedValue({ + claims: { + sub: 'test-gotrue-id', email: 'test@example.com', }, error: null, @@ -14,7 +14,7 @@ const mocks = vi.hoisted(() => { }) vi.mock('lib/gotrue', () => ({ - getAuthUser: mocks.getAuthUser, + getUserClaims: mocks.getUserClaims, })) describe('apiAuthenticate', () => { @@ -29,9 +29,9 @@ describe('apiAuthenticate', () => { beforeEach(() => { vi.clearAllMocks() - mocks.getAuthUser.mockResolvedValue({ - user: { - id: 'test-gotrue-id', + mocks.getUserClaims.mockResolvedValue({ + claims: { + sub: 'test-gotrue-id', email: 'test@example.com', }, error: null, @@ -45,8 +45,8 @@ describe('apiAuthenticate', () => { }) it('should return error when auth user fetch fails', async () => { - mocks.getAuthUser.mockResolvedValue({ - user: null, + mocks.getUserClaims.mockResolvedValue({ + claims: null, error: new Error('Auth failed'), }) @@ -55,8 +55,8 @@ describe('apiAuthenticate', () => { }) it('should return error when user does not exist', async () => { - mocks.getAuthUser.mockResolvedValue({ - user: null, + mocks.getUserClaims.mockResolvedValue({ + claims: null, error: null, }) diff --git a/apps/studio/lib/api/apiAuthenticate.ts b/apps/studio/lib/api/apiAuthenticate.ts index bcca2e361f4..02922dfd80c 100644 --- a/apps/studio/lib/api/apiAuthenticate.ts +++ b/apps/studio/lib/api/apiAuthenticate.ts @@ -1,6 +1,7 @@ -import { getAuthUser } from 'lib/gotrue' +import type { JwtPayload } from '@supabase/supabase-js' +import { getUserClaims } from 'lib/gotrue' import type { NextApiRequest, NextApiResponse } from 'next' -import type { ResponseError, SupaResponse, User } from 'types' +import type { ResponseError } from 'types' /** * Use this method on api routes to check if user is authenticated and having required permissions. @@ -15,14 +16,14 @@ import type { ResponseError, SupaResponse, User } from 'types' export async function apiAuthenticate( req: NextApiRequest, _res: NextApiResponse -): Promise> { +): Promise { try { - const user = await fetchUser(req) - if (!user) { + const claims = await fetchUserClaims(req) + if (!claims) { return { error: new Error('The user does not exist') } } - return user + return claims } catch (error) { return { error: error as ResponseError } } @@ -32,19 +33,19 @@ export async function apiAuthenticate( * @returns * user with only id prop or detail object. It depends on requireUserDetail config */ -async function fetchUser(req: NextApiRequest): Promise { - const token = req.headers.authorization?.replace('Bearer ', '') +async function fetchUserClaims(req: NextApiRequest): Promise { + const token = req.headers.authorization?.replace(/bearer /i, '') if (!token) { throw new Error('missing access token') } - const { user, error } = await getAuthUser(token) + const { claims, error } = await getUserClaims(token) if (error) { throw error } - if (!user) { + if (!claims) { throw new Error('The user does not exist') } - return user + return claims } diff --git a/apps/studio/lib/api/apiWrapper.ts b/apps/studio/lib/api/apiWrapper.ts index fb9d8bea327..901c5a5501b 100644 --- a/apps/studio/lib/api/apiWrapper.ts +++ b/apps/studio/lib/api/apiWrapper.ts @@ -40,9 +40,6 @@ export default async function apiWrapper( message: `Unauthorized: ${response.error.message}`, }, }) - } else { - // Attach user information to request parameters - ;(req as any).user = response } } diff --git a/apps/studio/lib/api/apiWrappers.test.ts b/apps/studio/lib/api/apiWrappers.test.ts index 0768780ef28..9fc8d326220 100644 --- a/apps/studio/lib/api/apiWrappers.test.ts +++ b/apps/studio/lib/api/apiWrappers.test.ts @@ -28,14 +28,4 @@ describe('apiWrapper', () => { expect(mockHandler).toHaveBeenCalledWith(mockReq, mockRes) expect(apiAuthenticate).not.toHaveBeenCalled() }) - - it('should attach user to request and call handler when authentication succeeds', async () => { - const mockUser = { id: '123', email: 'test@example.com' } as any as any - vi.mocked(apiAuthenticate).mockResolvedValue(mockUser) - - await apiWrapper(mockReq, mockRes, mockHandler, { withAuth: true }) - - expect(mockReq.user).toEqual(mockUser) - expect(mockHandler).toHaveBeenCalledWith(mockReq, mockRes) - }) }) diff --git a/apps/studio/lib/gotrue.ts b/apps/studio/lib/gotrue.ts index 42c65673ae6..b51fdd29e71 100644 --- a/apps/studio/lib/gotrue.ts +++ b/apps/studio/lib/gotrue.ts @@ -1,3 +1,4 @@ +import type { JwtPayload } from '@supabase/supabase-js' import { getAccessToken, type User } from 'common/auth' import { gotrueClient } from 'common/gotrue' @@ -23,18 +24,17 @@ export const validateReturnTo = ( return safePathPattern.test(returnTo) ? returnTo : fallback } -export const getAuthUser = async (token: String): Promise => { +export const getUserClaims = async ( + token: String +): Promise<{ error: any | null; claims: JwtPayload | null }> => { try { - const { - data: { user }, - error, - } = await auth.getUser(token.replace('Bearer ', '')) + const { data, error } = await auth.getClaims(token.replace(/bearer /i, '')) if (error) throw error - return { user, error: null } + return { claims: data?.claims ?? null, error: null } } catch (err) { console.error(err) - return { user: null, error: err } + return { claims: null, error: err } } }