Skip to content

Commit

Permalink
ENG-0000 fix(portal): updates privy redirect logic (#966)
Browse files Browse the repository at this point in the history
- Updates the Privy redirect logic to avoid early return `null`
- Co-authored-by: 0xjojikun <[email protected]>
  • Loading branch information
jonathanprozzi authored Dec 5, 2024
1 parent 98be168 commit 31d6745
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 22 deletions.
11 changes: 10 additions & 1 deletion apps/portal/app/.server/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -130,12 +130,21 @@ export async function handlePrivyRedirect({
return null
}

// First check if we're missing any tokens
if (!accessToken || !sessionToken) {
const redirectUrl = await getRedirectToUrl(request, path, options)
throw redirect(redirectUrl)
}

// Explicitly return null when we reach the end
// If we have both tokens, verify the access token
const verifiedClaims = await verifyPrivyAccessToken(request)
if (!verifiedClaims) {
// Token is invalid, redirect to refresh
const redirectUrl = await getRedirectToUrl(request, path, options)
throw redirect(redirectUrl)
}

// Only return null if we have valid tokens
return null
}

Expand Down
6 changes: 4 additions & 2 deletions apps/portal/app/.server/privy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,20 @@ export const verifyPrivyAccessToken = async (
): Promise<AuthTokenClaims | null> => {
const privy = getPrivyClient()
const authToken = getPrivyAccessToken(req)

if (!authToken) {
logger('No Privy access token found')
logger('[verifyPrivyAccessToken] No Privy access token found')
return null
}

try {
const verifiedClaims = await privy.verifyAuthToken(
authToken,
process.env.PRIVY_VERIFICATION_KEY,
)
return verifiedClaims
} catch (error) {
logger('Error verifying Privy access token', error)
logger('[verifyPrivyAccessToken] Error verifying Privy access token', error)
return null
}
}
Expand Down
54 changes: 36 additions & 18 deletions apps/portal/app/routes/_index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,38 +8,33 @@ import { PATHS } from 'app/consts'
export async function loader({ request }: LoaderFunctionArgs) {
getMaintenanceMode()

const cookieHeader = request.headers.get('Cookie')
const cookie = await onboardingModalCookie.parse(cookieHeader)
const redirectTo = new URL(request.url).searchParams.get('redirectTo')

const url = new URL(request.url)
const redirectTo = url.searchParams.get('redirectTo')
const isReadonlyRoute = url.pathname.startsWith('/readonly/')

if (isReadonlyRoute) {
return json({})
}

// Check onboarding first
const cookieHeader = request.headers.get('Cookie')
const cookie = await onboardingModalCookie.parse(cookieHeader)
if (!cookie) {
throw redirect('/intro')
}

const { accessToken, sessionToken } = getPrivyTokens(request)

// If we have an access token, verify it's still valid
if (accessToken) {
const verifiedClaims = await verifyPrivyAccessToken(request)
if (verifiedClaims) {
logger('[Loader] User is authenticated, redirecting to destination')
throw redirect(redirectTo || PATHS.HOME)
}
// Token exists but is invalid - continue to refresh flow
// No tokens at all - redirect to login
if (!accessToken && !sessionToken) {
logger('[Loader] No tokens present, redirecting to login')
throw redirect('/login')
}

// If we have a session token but no valid access token,
// redirect to refresh route to handle token refresh
if (sessionToken) {
// Has session token but no access token - needs refresh
if (!accessToken && sessionToken) {
logger(
'[Loader] Session token present but no valid access token, redirecting to refresh',
'[Loader] No access token but have session token, redirecting to refresh',
)
const refreshUrl = new URL('/refresh', request.url)
if (redirectTo) {
Expand All @@ -48,8 +43,31 @@ export async function loader({ request }: LoaderFunctionArgs) {
throw redirect(refreshUrl.toString())
}

// No tokens at all, redirect to login
logger('[Loader] No tokens present, redirecting to login')
// Verify access token if present
if (accessToken) {
const verifiedClaims = await verifyPrivyAccessToken(request)
if (verifiedClaims) {
logger('[Loader] Access token verified, redirecting to destination')
throw redirect(redirectTo || PATHS.HOME)
}

// Token is invalid - try refresh if we have session token
if (sessionToken) {
logger(
'[Loader] Access token invalid but have session token, redirecting to refresh',
)
const refreshUrl = new URL('/refresh', request.url)
if (redirectTo) {
refreshUrl.searchParams.set('redirectTo', redirectTo)
}
throw redirect(refreshUrl.toString())
}
}

// If we get here, we have an invalid access token and no session token
logger(
'[Loader] Invalid access token and no session token, redirecting to login',
)
throw redirect('/login')
}

Expand Down
2 changes: 1 addition & 1 deletion apps/portal/app/routes/intro+/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export async function loader() {
export async function action({ request }: ActionFunctionArgs) {
const redirectUrl = (await request.formData()).get('redirectUrl')

return redirect(typeof redirectUrl === 'string' ? redirectUrl : '/login', {
return redirect(typeof redirectUrl === 'string' ? redirectUrl : '/', {
headers: {
'Set-Cookie': await onboardingModalCookie.serialize({
dateOnboardingCompleted: new Date().valueOf(),
Expand Down

0 comments on commit 31d6745

Please sign in to comment.