Skip to content

Commit

Permalink
Detect if cross-site cookie config is needed
Browse files Browse the repository at this point in the history
Necessary if API_URL does not contain APP_URL.
  • Loading branch information
rmarscher committed Jan 5, 2024
1 parent 471dd9c commit 84189a1
Show file tree
Hide file tree
Showing 3 changed files with 25 additions and 13 deletions.
26 changes: 20 additions & 6 deletions packages/api/src/auth/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Adapter, DatabaseSessionAttributes, DatabaseUserAttributes, Lucia, Time
import { DrizzleSQLiteAdapter } from '@lucia-auth/adapter-drizzle'
import { SessionTable, UserTable } from '../db/schema'
import { DB } from '../db/client'
import type { ApiContextProps } from '../context'

/**
* Lucia's isValidRequestOrigin method will compare the
Expand All @@ -18,17 +19,29 @@ export const getAllowedOriginHost = (app_url: string, request?: Request) => {
return requestHost === appHost ? appHost : undefined
}

export const createAuth = (db: DB, appUrl: string) => {
export const isCrossDomain = (appUrl: string, apiUrl: string) => {
const appHost = new URL(appUrl).host
const apiHost = new URL(apiUrl).host
return !apiHost.endsWith(appHost)
}

export function getCookieOptions(ctx: ApiContextProps) {
return isCrossDomain(ctx.env.APP_URL, ctx.env.PUBLIC_API_URL)
? 'HttpOnly; SameSite=None; Secure;'
: 'HttpOnly; SameSite=Lax; Secure;'
}

export const createAuth = (db: DB, appUrl: string, apiUrl: string) => {
// @ts-ignore Expect type errors because this is D1 and not SQLite... but it works
const adapter = new DrizzleSQLiteAdapter(db, SessionTable, UserTable)
// cast probably only needed until adapter-drizzle is updated
// @ts-ignore the "none" option for sameSite works... but https://github.com/lucia-auth/lucia/issues/1320
return new Lucia(adapter as Adapter, {
...getAuthOptions(appUrl),
...getAuthOptions(appUrl, apiUrl),
})
}

export const getAuthOptions = (appUrl: string) => {
const env = !appUrl || appUrl.startsWith('http:') ? 'DEV' : 'PROD'
export const getAuthOptions = (appUrl: string, apiUrl: string) => {
return {
getUserAttributes: (data: DatabaseUserAttributes) => {
return {
Expand All @@ -45,8 +58,9 @@ export const getAuthOptions = (appUrl: string) => {
name: 'auth_session',
expires: false,
attributes: {
secure: env === 'PROD',
sameSite: 'lax' as const,
secure: true,
// This might not work forever https://github.com/lucia-auth/lucia/issues/1320
sameSite: isCrossDomain(appUrl, apiUrl) ? ('none' as const) : ('lax' as const),
},
},

Expand Down
7 changes: 3 additions & 4 deletions packages/api/src/auth/oauth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import { createAuthMethodId, createUser, getAuthMethod, getUserById } from './us
import { P, match } from 'ts-pattern'
import { getCookie } from 'hono/cookie'
import { TRPCError } from '@trpc/server'
import { getCookieOptions, isCrossDomain } from '.'

export interface AppleIdTokenClaims {
iss: 'https://appleid.apple.com'
Expand Down Expand Up @@ -101,15 +102,13 @@ export const getAuthorizationUrl = async (ctx: ApiContextProps, service: AuthPro
const provider = getAuthProvider(ctx, service)
const secure = ctx.req?.url.startsWith('https:') ? 'Secure; ' : ''
const state = generateState()
ctx.setCookie(
`${service}_oauth_state=${state}; Path=/; ${secure}HttpOnly; SameSite=Lax; Max-Age=600`
)
ctx.setCookie(`${service}_oauth_state=${state}; Path=/; ${getCookieOptions(ctx)} Max-Age=600`)
return await match({ provider, service })
.with({ service: 'google', provider: P.instanceOf(Google) }, async ({ provider }) => {
// Google requires PKCE
const codeVerifier = generateCodeVerifier()
ctx.setCookie(
`${service}_oauth_verifier=${codeVerifier}; Path=/; ${secure}HttpOnly; SameSite=Lax; Max-Age=600`
`${service}_oauth_verifier=${codeVerifier}; Path=/; ${getCookieOptions(ctx)} Max-Age=600`
)
const url = await provider.createAuthorizationURL(state, codeVerifier, {
scopes: ['https://www.googleapis.com/auth/userinfo.email'],
Expand Down
5 changes: 2 additions & 3 deletions packages/api/src/routes/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import { getCookie } from 'hono/cookie'
import { parseJWT } from 'oslo/jwt'
import { P, match } from 'ts-pattern'
import { AuthProviderName } from '../auth/providers'
import { getCookieOptions } from '../auth'

export function sanitizeUserIdInput<K extends keyof T, T>({
ctx,
Expand Down Expand Up @@ -229,9 +230,7 @@ const authorizationUrlHandler =
}
const secure = ctx.req?.url.startsWith('https:') ? 'Secure; ' : ''
ctx.setCookie(
`${input.provider}_oauth_redirect=${
input.redirectTo || ''
}; Path=/; ${secure}HttpOnly; SameSite=Lax`
`${input.provider}_oauth_redirect=${input.redirectTo || ''}; Path=/; ${getCookieOptions(ctx)}`
)
return { redirectTo: url.toString() }
}
Expand Down

0 comments on commit 84189a1

Please sign in to comment.