feat: use expo-secure-store and better-auth buildin getCookie for auth
This commit is contained in:
parent
0fc90c7c28
commit
accbf7fa60
|
|
@ -91,6 +91,7 @@ export default ({ config }: ConfigContext): ExpoConfig => ({
|
|||
"expo-apple-authentication",
|
||||
[require("./scripts/with-follow-assets.js")],
|
||||
[require("./scripts/with-follow-app-delegate.js")],
|
||||
"expo-secure-store",
|
||||
],
|
||||
experiments: {
|
||||
typedRoutes: true,
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@
|
|||
"expo-linear-gradient": "~14.0.1",
|
||||
"expo-linking": "~7.0.3",
|
||||
"expo-router": "4.0.11",
|
||||
"expo-secure-store": "^14.0.1",
|
||||
"expo-sharing": "~13.0.0",
|
||||
"expo-splash-screen": "~0.29.18",
|
||||
"expo-sqlite": "15.0.3",
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import type { AppType } from "@follow/shared"
|
|||
import { router } from "expo-router"
|
||||
import { ofetch } from "ofetch"
|
||||
|
||||
import { getSessionToken } from "./cookie"
|
||||
import { getCookie } from "./auth"
|
||||
import { getApiUrl } from "./env"
|
||||
|
||||
const { hc } = require("hono/dist/cjs/client/client") as typeof import("hono/client")
|
||||
|
|
@ -13,20 +13,10 @@ export const apiFetch = ofetch.create({
|
|||
|
||||
baseURL: getApiUrl(),
|
||||
onRequest: async ({ options, request }) => {
|
||||
const header = new Headers(options.headers)
|
||||
|
||||
header.set("x-app-name", "Follow Mobile")
|
||||
|
||||
const sessionToken = await getSessionToken()
|
||||
if (sessionToken) {
|
||||
header.set("cookie", `__Secure-better-auth.session_token=${sessionToken}`)
|
||||
}
|
||||
if (__DEV__) {
|
||||
// Logger
|
||||
console.log(`---> ${options.method} ${request as string}`)
|
||||
}
|
||||
|
||||
options.headers = header
|
||||
},
|
||||
onRequestError: ({ error, request, options }) => {
|
||||
if (__DEV__) {
|
||||
|
|
@ -60,6 +50,7 @@ export const apiClient = hc<AppType>(getApiUrl(), {
|
|||
headers() {
|
||||
return {
|
||||
"X-App-Name": "Follow Mobile",
|
||||
cookie: getCookie(),
|
||||
}
|
||||
},
|
||||
})
|
||||
|
|
|
|||
|
|
@ -2,11 +2,9 @@ import { expoClient } from "@better-auth/expo/client"
|
|||
import { useQuery } from "@tanstack/react-query"
|
||||
import { createAuthClient } from "better-auth/react"
|
||||
import type * as better_call from "better-call"
|
||||
import { parse } from "cookie-es"
|
||||
import * as SecureStore from "expo-secure-store"
|
||||
|
||||
import { getApiUrl } from "./env"
|
||||
import { kv } from "./kv"
|
||||
import { queryClient } from "./query-client"
|
||||
|
||||
const storagePrefix = "follow_auth"
|
||||
export const cookieKey = `${storagePrefix}_cookie`
|
||||
|
|
@ -22,17 +20,7 @@ const authClient = createAuthClient({
|
|||
expoClient({
|
||||
scheme: "follow",
|
||||
storagePrefix,
|
||||
storage: {
|
||||
setItem(key, value) {
|
||||
kv.setSync(key, value)
|
||||
if (key === cookieKey) {
|
||||
queryClient.invalidateQueries({ queryKey: ["cookie"] })
|
||||
}
|
||||
},
|
||||
getItem(key) {
|
||||
return kv.getSync(key)
|
||||
},
|
||||
},
|
||||
storage: SecureStore,
|
||||
}),
|
||||
],
|
||||
})
|
||||
|
|
@ -54,18 +42,6 @@ export const useAuthProviders = () => {
|
|||
})
|
||||
}
|
||||
|
||||
export const getSessionTokenFromCookie = () => {
|
||||
const cookie = getCookie()
|
||||
return cookie ? parse(cookie)[sessionTokenKey] : null
|
||||
}
|
||||
|
||||
export const useAuthToken = () => {
|
||||
return useQuery({
|
||||
queryKey: ["cookie"],
|
||||
queryFn: getSessionTokenFromCookie,
|
||||
})
|
||||
}
|
||||
|
||||
// eslint-disable-next-line unused-imports/no-unused-vars
|
||||
declare const authPlugins: {
|
||||
id: "getProviders"
|
||||
|
|
|
|||
|
|
@ -1,35 +0,0 @@
|
|||
import CookieManager from "@react-native-cookies/cookies"
|
||||
|
||||
import { cookieKey, getSessionTokenFromCookie, sessionTokenKey } from "./auth"
|
||||
import { getApiUrl } from "./env"
|
||||
import { kv } from "./kv"
|
||||
|
||||
export const setSessionToken = (token: string) => {
|
||||
kv.setSync(
|
||||
cookieKey,
|
||||
JSON.stringify({
|
||||
[sessionTokenKey]: {
|
||||
value: token,
|
||||
expires: new Date(Date.now() + 1000 * 60 * 60 * 24 * 365).toISOString(),
|
||||
},
|
||||
}),
|
||||
)
|
||||
|
||||
return CookieManager.set(getApiUrl(), {
|
||||
name: sessionTokenKey,
|
||||
value: token,
|
||||
httpOnly: true,
|
||||
secure: true,
|
||||
})
|
||||
}
|
||||
|
||||
export const getSessionToken = async () => {
|
||||
const cookies = await CookieManager.get(getApiUrl())
|
||||
|
||||
return cookies[sessionTokenKey] || getSessionTokenFromCookie()
|
||||
}
|
||||
|
||||
export const clearSessionToken = async () => {
|
||||
await kv.delete(cookieKey)
|
||||
return CookieManager.clearAll()
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@ import { sleep } from "@follow/utils"
|
|||
import * as Clipboard from "expo-clipboard"
|
||||
import * as FileSystem from "expo-file-system"
|
||||
import { Sitemap } from "expo-router/build/views/Sitemap"
|
||||
import * as SecureStore from "expo-secure-store"
|
||||
import type { FC } from "react"
|
||||
import * as React from "react"
|
||||
import { useRef, useState } from "react"
|
||||
|
|
@ -18,7 +19,7 @@ import {
|
|||
import { useSafeAreaInsets } from "react-native-safe-area-context"
|
||||
|
||||
import { getDbPath } from "@/src/database"
|
||||
import { clearSessionToken, getSessionToken, setSessionToken } from "@/src/lib/cookie"
|
||||
import { cookieKey, getCookie, sessionTokenKey, signOut } from "@/src/lib/auth"
|
||||
import { loading } from "@/src/lib/loading"
|
||||
import { toast } from "@/src/lib/toast"
|
||||
|
||||
|
|
@ -44,14 +45,14 @@ export default function DebugPanel() {
|
|||
{
|
||||
title: "Get Current Session Token",
|
||||
onPress: async () => {
|
||||
const token = await getSessionToken()
|
||||
Alert.alert(`Current Session Token: ${token?.value}`)
|
||||
const token = getCookie()
|
||||
Alert.alert(`Current Session Token: ${token}`)
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "Clear Session Token",
|
||||
onPress: async () => {
|
||||
await clearSessionToken()
|
||||
await signOut()
|
||||
Alert.alert("Session Token Cleared")
|
||||
},
|
||||
},
|
||||
|
|
@ -178,7 +179,14 @@ const UserSessionSetting = () => {
|
|||
<TouchableOpacity
|
||||
className="ml-2"
|
||||
onPress={() => {
|
||||
setSessionToken(input)
|
||||
SecureStore.setItem(
|
||||
cookieKey,
|
||||
JSON.stringify({
|
||||
[sessionTokenKey]: {
|
||||
value: input,
|
||||
},
|
||||
}),
|
||||
)
|
||||
Alert.alert("Session Token Saved")
|
||||
}}
|
||||
>
|
||||
|
|
|
|||
|
|
@ -1,41 +1,38 @@
|
|||
import { Redirect } from "expo-router"
|
||||
import { useEffect, useRef, useState } from "react"
|
||||
import { useRef } from "react"
|
||||
import { TouchableOpacity, View } from "react-native"
|
||||
import { useSafeAreaInsets } from "react-native-safe-area-context"
|
||||
import type { WebView } from "react-native-webview"
|
||||
|
||||
import { FollowWebView } from "@/src/components/common/FollowWebView"
|
||||
import { BugCuteReIcon } from "@/src/icons/bug_cute_re"
|
||||
import { ExitCuteReIcon } from "@/src/icons/exit_cute_re"
|
||||
import { Refresh2CuteReIcon } from "@/src/icons/refresh_2_cute_re"
|
||||
import { World2CuteReIcon } from "@/src/icons/world_2_cute_re"
|
||||
import { signOut, useAuthToken } from "@/src/lib/auth"
|
||||
import { setSessionToken } from "@/src/lib/cookie"
|
||||
import { signOut } from "@/src/lib/auth"
|
||||
|
||||
export default function Index() {
|
||||
const webViewRef = useRef<WebView>(null)
|
||||
const insets = useSafeAreaInsets()
|
||||
|
||||
const { data: token, isPending } = useAuthToken()
|
||||
// const { data: token, isPending } = useAuthToken()
|
||||
|
||||
const [isCookieReady, setIsCookieReady] = useState(false)
|
||||
useEffect(() => {
|
||||
if (!token) {
|
||||
return
|
||||
}
|
||||
// const [isCookieReady, setIsCookieReady] = useState(false)
|
||||
// useEffect(() => {
|
||||
// if (!token) {
|
||||
// return
|
||||
// }
|
||||
|
||||
setSessionToken(token).then(() => {
|
||||
setIsCookieReady(true)
|
||||
})
|
||||
}, [token])
|
||||
// // setSessionToken(token).then(() => {
|
||||
// // setIsCookieReady(true)
|
||||
// // })
|
||||
// }, [token])
|
||||
|
||||
if (!token && !isPending) {
|
||||
return <Redirect href="/login" />
|
||||
}
|
||||
// if (!token && !isPending) {
|
||||
// return <Redirect href="/login" />
|
||||
// }
|
||||
|
||||
return (
|
||||
<View className="flex-1 items-center justify-center pt-safe dark:bg-[#121212]">
|
||||
{isCookieReady && <FollowWebView webViewRef={webViewRef} />}
|
||||
{/* {isCookieReady && <FollowWebView webViewRef={webViewRef} />} */}
|
||||
|
||||
{__DEV__ && (
|
||||
<View
|
||||
|
|
|
|||
|
|
@ -508,6 +508,9 @@ importers:
|
|||
expo-router:
|
||||
specifier: 4.0.11
|
||||
version: 4.0.11(4kc7a2oyapueyif6rxtpvh4774)
|
||||
expo-secure-store:
|
||||
specifier: ^14.0.1
|
||||
version: 14.0.1(expo@52.0.18(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@expo/metro-runtime@4.0.0(react-native@0.76.5(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@react-native-community/cli-server-api@14.1.0(bufferutil@4.0.8))(@types/react@18.3.14)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)))(bufferutil@4.0.8)(encoding@0.1.13)(graphql@16.8.1)(react-native-webview@13.12.5(react-native@0.76.5(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@react-native-community/cli-server-api@14.1.0(bufferutil@4.0.8))(@types/react@18.3.14)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1))(react@18.3.1))(react-native@0.76.5(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@react-native-community/cli-server-api@14.1.0(bufferutil@4.0.8))(@types/react@18.3.14)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1))(react@18.3.1))
|
||||
expo-sharing:
|
||||
specifier: ~13.0.0
|
||||
version: 13.0.0(expo@52.0.18(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@expo/metro-runtime@4.0.0(react-native@0.76.5(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@react-native-community/cli-server-api@14.1.0(bufferutil@4.0.8))(@types/react@18.3.14)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)))(bufferutil@4.0.8)(encoding@0.1.13)(graphql@16.8.1)(react-native-webview@13.12.5(react-native@0.76.5(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@react-native-community/cli-server-api@14.1.0(bufferutil@4.0.8))(@types/react@18.3.14)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1))(react@18.3.1))(react-native@0.76.5(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@react-native-community/cli-server-api@14.1.0(bufferutil@4.0.8))(@types/react@18.3.14)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1))(react@18.3.1))
|
||||
|
|
@ -8859,6 +8862,11 @@ packages:
|
|||
react-native-reanimated:
|
||||
optional: true
|
||||
|
||||
expo-secure-store@14.0.1:
|
||||
resolution: {integrity: sha512-QUS+j4+UG4jRQalgnpmTvvrFnMVLqPiUZRzYPnG3+JrZ5kwVW2w6YS3WWerPoR7C6g3y/a2htRxRSylsDs+TaQ==}
|
||||
peerDependencies:
|
||||
expo: '*'
|
||||
|
||||
expo-sharing@13.0.0:
|
||||
resolution: {integrity: sha512-b23ymicRmYn/Pjj05sl9tFZHN5cH9I1f0yiqY1Yk8Q3oCx0Aznri82DnTYA4T/J6D9vrkraX0wQ4jWVMOffmlg==}
|
||||
peerDependencies:
|
||||
|
|
@ -24823,6 +24831,10 @@ snapshots:
|
|||
- supports-color
|
||||
- typescript
|
||||
|
||||
expo-secure-store@14.0.1(expo@52.0.18(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@expo/metro-runtime@4.0.0(react-native@0.76.5(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@react-native-community/cli-server-api@14.1.0(bufferutil@4.0.8))(@types/react@18.3.14)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)))(bufferutil@4.0.8)(encoding@0.1.13)(graphql@16.8.1)(react-native-webview@13.12.5(react-native@0.76.5(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@react-native-community/cli-server-api@14.1.0(bufferutil@4.0.8))(@types/react@18.3.14)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1))(react@18.3.1))(react-native@0.76.5(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@react-native-community/cli-server-api@14.1.0(bufferutil@4.0.8))(@types/react@18.3.14)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1))(react@18.3.1)):
|
||||
dependencies:
|
||||
expo: 52.0.18(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@expo/metro-runtime@4.0.0(react-native@0.76.5(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@react-native-community/cli-server-api@14.1.0(bufferutil@4.0.8))(@types/react@18.3.14)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)))(bufferutil@4.0.8)(encoding@0.1.13)(graphql@16.8.1)(react-native-webview@13.12.5(react-native@0.76.5(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@react-native-community/cli-server-api@14.1.0(bufferutil@4.0.8))(@types/react@18.3.14)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1))(react@18.3.1))(react-native@0.76.5(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@react-native-community/cli-server-api@14.1.0(bufferutil@4.0.8))(@types/react@18.3.14)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1))(react@18.3.1)
|
||||
|
||||
expo-sharing@13.0.0(expo@52.0.18(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@expo/metro-runtime@4.0.0(react-native@0.76.5(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@react-native-community/cli-server-api@14.1.0(bufferutil@4.0.8))(@types/react@18.3.14)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)))(bufferutil@4.0.8)(encoding@0.1.13)(graphql@16.8.1)(react-native-webview@13.12.5(react-native@0.76.5(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@react-native-community/cli-server-api@14.1.0(bufferutil@4.0.8))(@types/react@18.3.14)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1))(react@18.3.1))(react-native@0.76.5(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@react-native-community/cli-server-api@14.1.0(bufferutil@4.0.8))(@types/react@18.3.14)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1))(react@18.3.1)):
|
||||
dependencies:
|
||||
expo: 52.0.18(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@expo/metro-runtime@4.0.0(react-native@0.76.5(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@react-native-community/cli-server-api@14.1.0(bufferutil@4.0.8))(@types/react@18.3.14)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1)))(bufferutil@4.0.8)(encoding@0.1.13)(graphql@16.8.1)(react-native-webview@13.12.5(react-native@0.76.5(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@react-native-community/cli-server-api@14.1.0(bufferutil@4.0.8))(@types/react@18.3.14)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1))(react@18.3.1))(react-native@0.76.5(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@react-native-community/cli-server-api@14.1.0(bufferutil@4.0.8))(@types/react@18.3.14)(bufferutil@4.0.8)(encoding@0.1.13)(react@18.3.1))(react@18.3.1)
|
||||
|
|
|
|||
Loading…
Reference in New Issue