mirror of
https://github.com/supabase/supabase.git
synced 2026-10-05 09:25:06 +03:00
fix: local api route fixes (#35642)
* fix: local api route fixes * fix build * fix tests * address feedback * remove unused debug
This commit is contained in:
1 parent
bc4ca2e275
commit
6c83f97478
18 files changed
+67
-890
No files matched your search
@@ -1,44 +1,30 @@
|
||||
import { getAuthUser } from 'lib/gotrue'
|
||||
import type { NextApiRequest, NextApiResponse } from 'next'
|
||||
import { readOnly } from './supabaseClient'
|
||||
import type { SupaResponse, User } from 'types'
|
||||
import { getAuth0Id, getAuthUser, getIdentity } from 'lib/gotrue'
|
||||
import type { ResponseError, SupaResponse, User } from 'types'
|
||||
|
||||
/**
|
||||
* Use this method on api routes to check if user is authenticated and having required permissions.
|
||||
* This method can only be used from the server side.
|
||||
* Member permission is mandatory whenever orgSlug/projectRef query param exists
|
||||
* @param {NextApiRequest} req
|
||||
* @param {NextApiResponse} res
|
||||
* @param {Object} config requireUserDetail: bool, requireOwner: bool
|
||||
* @param {NextApiResponse} _res
|
||||
*
|
||||
* @returns {Object<user, error, description>}
|
||||
* user null, with error and description if not authenticated or not enough permissions
|
||||
*/
|
||||
export async function apiAuthenticate(
|
||||
req: NextApiRequest,
|
||||
res: NextApiResponse
|
||||
_res: NextApiResponse
|
||||
): Promise<SupaResponse<User>> {
|
||||
if (!req) {
|
||||
return { error: new Error('Request is not available') }
|
||||
}
|
||||
|
||||
if (!res) {
|
||||
return { error: new Error('Response is not available') }
|
||||
}
|
||||
|
||||
const { slug: orgSlug, ref: projectRef } = req.query
|
||||
try {
|
||||
const user = await fetchUser(req, res)
|
||||
const user = await fetchUser(req)
|
||||
if (!user) {
|
||||
return { error: new Error('The user does not exist') }
|
||||
}
|
||||
|
||||
if (orgSlug || projectRef) await checkMemberPermission(req, user)
|
||||
|
||||
return user
|
||||
} catch (error: any) {
|
||||
console.error('Error at apiAuthenticate', error)
|
||||
return { error: { name: 'Error', message: error.message ?? 'unknown' } }
|
||||
} catch (error) {
|
||||
return { error: error as ResponseError }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,93 +32,19 @@ export async function apiAuthenticate(
|
||||
* @returns
|
||||
* user with only id prop or detail object. It depends on requireUserDetail config
|
||||
*/
|
||||
async function fetchUser(req: NextApiRequest, res: NextApiResponse): Promise<any> {
|
||||
let user_id_supabase = null
|
||||
let user_id_auth0 = null
|
||||
let gotrue_id = null
|
||||
let email = null
|
||||
|
||||
const token = req.headers.authorization
|
||||
async function fetchUser(req: NextApiRequest): Promise<any> {
|
||||
const token = req.headers.authorization?.replace('Bearer ', '')
|
||||
if (!token) {
|
||||
throw new Error('missing access token')
|
||||
}
|
||||
let { user: gotrue_user, error: authError } = await getAuthUser(token)
|
||||
if (authError) {
|
||||
throw authError
|
||||
}
|
||||
if (gotrue_user !== null) {
|
||||
gotrue_id = gotrue_user?.id
|
||||
email = gotrue_user.email
|
||||
|
||||
let { identity, error } = getIdentity(gotrue_user)
|
||||
if (error) throw error
|
||||
if (identity?.provider !== undefined) {
|
||||
user_id_auth0 = getAuth0Id(identity?.provider, identity?.id)
|
||||
}
|
||||
const { user, error } = await getAuthUser(token)
|
||||
if (error) {
|
||||
throw error
|
||||
}
|
||||
|
||||
if (user_id_supabase) {
|
||||
return {
|
||||
id: user_id_supabase,
|
||||
primary_email: email,
|
||||
}
|
||||
if (!user) {
|
||||
throw new Error('The user does not exist')
|
||||
}
|
||||
|
||||
const query = readOnly.from('users').select(
|
||||
`
|
||||
id, auth0_id, primary_email, username, first_name, last_name, mobile, is_alpha_user
|
||||
`
|
||||
)
|
||||
|
||||
const { data } = await query.eq('gotrue_id', gotrue_id).single()
|
||||
return data
|
||||
}
|
||||
|
||||
async function checkMemberPermission(req: NextApiRequest, user: any) {
|
||||
const org = await getOrganization(req)
|
||||
if (!org) {
|
||||
throw new Error('User organization does not exist')
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await readOnly
|
||||
.from('members')
|
||||
.select('id')
|
||||
.match({ organization_id: org.id, user_id: user.id })
|
||||
.single()
|
||||
|
||||
if (!response || response.status != 200) {
|
||||
throw new Error('The user does not have permission')
|
||||
}
|
||||
return true
|
||||
} catch (error) {
|
||||
throw new Error('The user does not have permission')
|
||||
}
|
||||
}
|
||||
|
||||
async function getOrganization(req: NextApiRequest) {
|
||||
const { slug: orgSlug, ref: projectRef } = req.query
|
||||
if (!orgSlug && !projectRef) {
|
||||
throw new Error('Not enough info to check user permissions')
|
||||
}
|
||||
|
||||
if (orgSlug) {
|
||||
const { data } = await readOnly
|
||||
.from('organizations')
|
||||
.select('id')
|
||||
.match({ slug: orgSlug })
|
||||
.single()
|
||||
return { id: data.id }
|
||||
}
|
||||
|
||||
if (projectRef) {
|
||||
const { data } = await readOnly
|
||||
.from('projects')
|
||||
.select('organization_id')
|
||||
.match({ ref: projectRef })
|
||||
.single()
|
||||
return { id: data.organization_id }
|
||||
}
|
||||
|
||||
return null
|
||||
return user
|
||||
}
|
||||
Reference in new issue
Block a user