Skip to content

Commit 691e9e0

Browse files
committed
revert: remove mobile auth cookie fallback
1 parent 321c4b6 commit 691e9e0

File tree

2 files changed

+38
-214
lines changed

2 files changed

+38
-214
lines changed

apps/mobile/src/lib/auth.ts

Lines changed: 1 addition & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
1-
import { expoClient, getSetCookie, hasBetterAuthCookies } from "@better-auth/expo/client"
1+
import { expoClient } from "@better-auth/expo/client"
22
import { baseAuthPlugins } from "@follow/shared/auth"
33
import { isNewUserQueryKey } from "@follow/store/user/constants"
44
import { whoamiQueryKey } from "@follow/store/user/hooks"
55
import { createMobileAPIHeaders } from "@follow/utils/headers"
66
import { useQuery } from "@tanstack/react-query"
77
import { createAuthClient } from "better-auth/react"
8-
import { fetch as expoFetch } from "expo/fetch"
98
import { nativeApplicationVersion } from "expo-application"
109
import * as FileSystem from "expo-file-system/legacy"
1110
import Storage from "expo-sqlite/kv-store"
@@ -73,48 +72,10 @@ const plugins = [
7372
}),
7473
]
7574

76-
const updateCookieStorage = (serializedCookie: string) => {
77-
try {
78-
safeSecureStore.setItem(cookieKey, serializedCookie)
79-
} catch (error) {
80-
console.warn("SecureStore.setItem failed during auth cookie persistence:", error)
81-
return false
82-
}
83-
84-
const env = getEnvProfile()
85-
try {
86-
safeSecureStore.setItem(`${cookieKey}_${env}`, serializedCookie)
87-
} catch {
88-
// Keychain may be unavailable in background
89-
}
90-
91-
bumpAuthStateRevision()
92-
queryClient.invalidateQueries({ queryKey: whoamiQueryKey })
93-
queryClient.invalidateQueries({ queryKey: isNewUserQueryKey })
94-
return true
95-
}
96-
97-
export const persistAuthCookieHeader = (setCookie: string | null | undefined) => {
98-
if (!setCookie || !hasBetterAuthCookies(setCookie, "better-auth")) {
99-
return false
100-
}
101-
102-
let previousCookie: string | undefined
103-
try {
104-
previousCookie = safeSecureStore.getItem(cookieKey) ?? undefined
105-
} catch (error) {
106-
console.warn("SecureStore.getItem failed during auth cookie persistence:", error)
107-
}
108-
109-
const serializedCookie = getSetCookie(setCookie, previousCookie)
110-
return updateCookieStorage(serializedCookie)
111-
}
112-
11375
export const authClient = createAuthClient({
11476
baseURL: `${proxyEnv.API_URL}/better-auth`,
11577
fetchOptions: {
11678
cache: "no-store",
117-
customFetchImpl: async (input, init) => expoFetch(input.toString(), init as any) as any,
11879
// Learn more: https://better-fetch.vercel.app/docs/hooks
11980
onRequest: async (ctx) => {
12081
const headers = createMobileAPIHeaders({

apps/mobile/src/modules/login/email.tsx

Lines changed: 37 additions & 174 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import { userSyncService } from "@follow/store/user/store"
21
import { tracker } from "@follow/tracker"
32
import { zodResolver } from "@hookform/resolvers/zod"
43
import { useMutation } from "@tanstack/react-query"
@@ -15,7 +14,7 @@ import { z } from "zod"
1514
import { SubmitButton } from "@/src/components/common/SubmitButton"
1615
import { PlainTextField } from "@/src/components/ui/form/TextField"
1716
import { Text } from "@/src/components/ui/typography/Text"
18-
import { authClient, persistAuthCookieHeader } from "@/src/lib/auth"
17+
import { signIn, signUp } from "@/src/lib/auth"
1918
import { useNavigation } from "@/src/lib/navigation/hooks"
2019
import { Navigation } from "@/src/lib/navigation/Navigation"
2120
import { toast } from "@/src/lib/toast"
@@ -30,134 +29,6 @@ const formSchema = z.object({
3029
})
3130
type FormValue = z.infer<typeof formSchema>
3231

33-
const getAuthErrorMessage = (value: unknown) => {
34-
if (!value || typeof value !== "object" || !("error" in value)) {
35-
return
36-
}
37-
38-
const { error } = value
39-
if (!error || typeof error !== "object" || !("message" in error)) {
40-
return
41-
}
42-
43-
return typeof error.message === "string" ? error.message : undefined
44-
}
45-
46-
const getAuthData = (value: unknown) => {
47-
if (!value || typeof value !== "object" || !("data" in value)) {
48-
return
49-
}
50-
51-
return value.data && typeof value.data === "object" ? value.data : undefined
52-
}
53-
54-
const getResponseSetCookie = (response: Response) => {
55-
const directValue =
56-
response.headers.get("x-better-auth-set-cookie") ??
57-
response.headers.get("set-cookie") ??
58-
response.headers.get("Set-Cookie")
59-
if (directValue) {
60-
return directValue
61-
}
62-
63-
const rawHeaders = (response as Response & { _rawHeaders?: unknown })._rawHeaders
64-
if (!Array.isArray(rawHeaders)) {
65-
return null
66-
}
67-
68-
const values = rawHeaders
69-
.filter(
70-
(header): header is [string, string] =>
71-
Array.isArray(header) &&
72-
header.length >= 2 &&
73-
typeof header[0] === "string" &&
74-
typeof header[1] === "string",
75-
)
76-
.filter(([key]) => key.toLowerCase() === "set-cookie")
77-
.map(([, value]) => value)
78-
79-
return values.length > 0 ? values.join(", ") : null
80-
}
81-
82-
const hasTwoFactorRedirect = (value: unknown) => {
83-
const data = getAuthData(value)
84-
if (data && "twoFactorRedirect" in data) {
85-
return Boolean(data.twoFactorRedirect)
86-
}
87-
88-
if (!value || typeof value !== "object" || !("response" in value)) {
89-
return false
90-
}
91-
92-
const { response } = value
93-
if (!response || typeof response !== "object" || !("twoFactorRedirect" in response)) {
94-
return false
95-
}
96-
97-
return Boolean(response.twoFactorRedirect)
98-
}
99-
100-
const requestCredentialAuth = async ({
101-
path,
102-
body,
103-
}: {
104-
path: "/sign-in/email" | "/sign-up/email"
105-
body: Record<string, string>
106-
}) => {
107-
let setCookie: string | null = null
108-
109-
const result = await authClient.$fetch(path, {
110-
method: "POST",
111-
body,
112-
headers: await getTokenHeaders(),
113-
throw: false,
114-
onResponse(context) {
115-
setCookie = getResponseSetCookie(context.response)
116-
},
117-
})
118-
119-
const persistedCookie = setCookie ? persistAuthCookieHeader(setCookie) : false
120-
121-
return {
122-
result,
123-
persistedCookie,
124-
}
125-
}
126-
127-
const establishCredentialSession = async ({
128-
email,
129-
password,
130-
onTwoFactorRedirect,
131-
}: {
132-
email: string
133-
password: string
134-
onTwoFactorRedirect?: () => void
135-
}) => {
136-
const { result, persistedCookie } = await requestCredentialAuth({
137-
path: "/sign-in/email",
138-
body: {
139-
email,
140-
password,
141-
},
142-
})
143-
144-
const errorMessage = getAuthErrorMessage(result)
145-
if (errorMessage) {
146-
throw new Error(errorMessage)
147-
}
148-
149-
if (hasTwoFactorRedirect(result)) {
150-
onTwoFactorRedirect?.()
151-
return null
152-
}
153-
154-
const session = persistedCookie ? await userSyncService.whoami().catch(() => null) : null
155-
if (!session?.user?.id) {
156-
return null
157-
}
158-
159-
return session
160-
}
16132
async function onSubmit(values: FormValue) {
16233
const result = formSchema.safeParse(values)
16334
if (!result.success) {
@@ -166,29 +37,37 @@ async function onSubmit(values: FormValue) {
16637
return false
16738
}
16839

169-
let session = null
17040
try {
171-
session = await establishCredentialSession({
172-
email: result.data.email,
173-
password: result.data.password,
174-
onTwoFactorRedirect: () => {
175-
Navigation.rootNavigation.presentControllerView(TwoFactorAuthScreen)
41+
const res = await signIn.email(
42+
{
43+
email: result.data.email,
44+
password: result.data.password,
17645
},
177-
})
46+
{
47+
headers: await getTokenHeaders(),
48+
},
49+
)
50+
51+
if (res.error) {
52+
throw new Error(res.error.message)
53+
}
54+
55+
// @ts-expect-error better-auth response type omits twoFactorRedirect
56+
if (res.data?.twoFactorRedirect) {
57+
Navigation.rootNavigation.presentControllerView(TwoFactorAuthScreen)
58+
return false
59+
}
17860
} catch (error) {
17961
Alert.alert(error instanceof Error ? error.message : "Unable to sign in")
18062
return false
18163
}
18264

183-
if (!session?.user?.id) {
184-
return false
185-
}
186-
18765
tracker.userLogin({
18866
type: "email",
18967
})
19068
return true
19169
}
70+
19271
export function EmailLogin() {
19372
const { t } = useTranslation()
19473
const [emailValue, setEmailValue] = useState("")
@@ -314,44 +193,28 @@ export function EmailSignUp() {
314193
})
315194
const submitMutation = useMutation({
316195
mutationFn: async (values: SignupFormValue) => {
317-
try {
318-
const { result, persistedCookie } = await requestCredentialAuth({
319-
path: "/sign-up/email",
320-
body: {
196+
await signUp
197+
.email(
198+
{
321199
email: values.email,
322200
password: values.password,
323201
name: values.email.split("@")[0] ?? "",
324202
},
203+
{
204+
headers: await getTokenHeaders(),
205+
},
206+
)
207+
.then((res) => {
208+
if (res.error?.message) {
209+
toast.error(res.error.message)
210+
} else {
211+
toast.success(i18next.t("login.sign_up_successful"))
212+
tracker.register({
213+
type: "email",
214+
})
215+
Navigation.rootNavigation.back()
216+
}
325217
})
326-
327-
const errorMessage = getAuthErrorMessage(result)
328-
if (errorMessage) {
329-
toast.error(errorMessage)
330-
return false
331-
}
332-
333-
let session = persistedCookie ? await userSyncService.whoami().catch(() => null) : null
334-
if (!session?.user?.id) {
335-
session = await establishCredentialSession({
336-
email: values.email,
337-
password: values.password,
338-
})
339-
}
340-
341-
if (!session?.user?.id) {
342-
toast.error("Unable to establish session after sign up")
343-
return false
344-
}
345-
346-
toast.success(i18next.t("login.sign_up_successful"))
347-
tracker.register({
348-
type: "email",
349-
})
350-
return true
351-
} catch (error) {
352-
toast.error(error instanceof Error ? error.message : "Unable to sign up")
353-
return false
354-
}
355218
},
356219
})
357220
const signup = handleSubmit((values) => {

0 commit comments

Comments
 (0)