BA
Better Auth•5mo ago
ak11

Offline support for expo apps

so i'm building an expo app that is to be built on iOS, android as well as to be deployed on the web. i moved away from clerk seeing they've not made enough progress in heir offline support. i need guidance on what to do. i'm tring to build a local first business management tool and one of my requirements is that iw ould want to be able to open my application without necessarily having an internet connection. i thought with the sessions being stored on the user device using expo-securestore i thought that would be a possibility, but it's not. please your help would be very much appreciated
18 Replies
ak11
ak11OP•5mo ago
this is my current protecteRoute set's up that wraps the entry of my app
import React, { useEffect } from 'react';
import { router, useSegments } from 'expo-router';
import { authClient } from '@/authClient';

interface ProtectedRouteProps {
children: React.ReactNode;
}

export const ProtectedRoute: React.FC<ProtectedRouteProps> = ({ children }) => {
const { data: session, isPending: isSessionPending } =
authClient.useSession();
const { data: activeOrg, isPending: isOrgPending } =
authClient.useActiveOrganization();

const segments = useSegments();

useEffect(() => {
if (!session && !isSessionPending) {
router.push('/sign-in');
}
if (
!session &&
!isSessionPending &&
!activeOrg &&
!isOrgPending &&
segments[0] !== '(org-list)'
) {
router.push('/recent-businesses');
}
}, [session, isSessionPending, activeOrg, isOrgPending]);

if (!session) return null;

return children;
};
import React, { useEffect } from 'react';
import { router, useSegments } from 'expo-router';
import { authClient } from '@/authClient';

interface ProtectedRouteProps {
children: React.ReactNode;
}

export const ProtectedRoute: React.FC<ProtectedRouteProps> = ({ children }) => {
const { data: session, isPending: isSessionPending } =
authClient.useSession();
const { data: activeOrg, isPending: isOrgPending } =
authClient.useActiveOrganization();

const segments = useSegments();

useEffect(() => {
if (!session && !isSessionPending) {
router.push('/sign-in');
}
if (
!session &&
!isSessionPending &&
!activeOrg &&
!isOrgPending &&
segments[0] !== '(org-list)'
) {
router.push('/recent-businesses');
}
}, [session, isSessionPending, activeOrg, isOrgPending]);

if (!session) return null;

return children;
};
Could you help please? @Ping
Ping
Ping•5mo ago
Sorry I don't have much experience in Expo. 😅 Maybe @bekacru could help?
ak11
ak11OP•5mo ago
okay hhey @bekacru
Vince
Vince•3mo ago
@ak11 did you find a solution to this?
ak11
ak11OP•3mo ago
yes, i just needed to setup the session config in my auth.ts session: { expiresIn: 60 * 60 * 24 * 14, // 7 days updateAge: 60 * 60 * 24 * 3, // 1 day (every 1 day the session expiration is updated) cookieCache: { enabled: false, maxAge: 24 * 60 * 60 * 2, // Cache duration in seconds }, }, advanced: { cookies: { session_token: { attributes: { httpOnly: true, // secure: process.env.NODE_ENV !== 'development', secure: true, sameSite: 'none', }, }, }, defaultCookieAttributes: { httpOnly: true, // secure: process.env.NODE_ENV !== 'development', secure: true, }, },
Vince
Vince•3mo ago
but authClient.useSession() will still try call the api instead of returning the cached value when no internet is available. I was under the impression that your usecase would also be using the cached session until internet is available again or the expiresIn is elapsed
ak11
ak11OP•3mo ago
it gets the cached value instead. or at least it’s supposed to
Vince
Vince•3mo ago
something might be botched with code then.. Just to reiterate, the code you wrote above goes into the server side auth config, the expo auth client stays the same and every call to authClient.useSession() should use the cached value? const {data: sessionData, isPending} = authClient.useSession(); sessionData stays null for me :/
Mendy Landa
Mendy Landa•2w ago
@Vince did you end up resolving the issue?
Vince
Vince•2w ago
Kinda. Since I want the app to be online but not always require internet access, I just used secure storage to basically keep track of if and how long a user should be logged in (while being offline). This hook will fetch the session from the server if it has internet connection and use an offline value if it has no internet connection. Additionally, after a defined time has passed (for example 7 days) it will invalidate the local login session and tell the user to log in again I'm happy with that solution but I would prefer if better-auth would handle this and I could just keep using the authClient.useSession() hook tbh
Mendy Landa
Mendy Landa•2w ago
Yeah I thought of implementing myself. So I understand the out of the box behavior still doesn’t cache the session
Vince
Vince•2w ago
I have not updated the packages in my project since I wrote here the last time. It might be different now but I don't know tbh - got sidetracked with work 😉
Mendy Landa
Mendy Landa•2w ago
BTW, do you think this needs to be stored in a secure way or is the session data not really that sensitive? Basically my question is do you think that AsyncStorage is enough for this use case?
Vince
Vince•2w ago
I mean all access to the backend will still be authenticated so even if the user managed to play around with the values, it probably wouldn't hurt. But I like to minimize the attack vectors so I just used SecureStorage. If you go with AsyncStorage I think there is a great writeup floating around somewhere that uses it together with Zustand for a really seamless experience
Mendy Landa
Mendy Landa•2w ago
Got it. Great help! Thanks mate
Billy
Billy•2w ago
Can you share the hook you wrote with the SecureStorage fallback? I see the expoClient plugin has a storage parameter but it doesn't seem that it's actually using that for the fallback.
Mendy Landa
Mendy Landa•4d ago
Here’s mine. Tf I need nitro to paste a long message?
Mendy Landa
Mendy Landa•4d ago
Gist
better-auth & expo, offline support
better-auth & expo, offline support . GitHub Gist: instantly share code, notes, and snippets.

Did you find this page helpful?