Skip to content
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
d2b8ed0
feat(auth): migrate to Better Auth + OAuth 2.1 for MCP
andrew-bierman May 1, 2026
8e6cf90
fix(auth): replace raw typeof checks with @packrat/guards
andrew-bierman May 1, 2026
561b40c
fix(mcp): replace raw regex literals with magic-regexp + fix TS casts
andrew-bierman May 1, 2026
22e392c
chore(deps): move magic-regexp to workspace catalog
andrew-bierman May 1, 2026
6dafda0
fix(api): restore isAuthenticated on alltrails preview route
andrew-bierman May 1, 2026
d7c5a45
chore: sort apps/expo/package.json keys
andrew-bierman May 1, 2026
ef16d99
fix(casts): add safe-cast annotations to pass strict cast checker
andrew-bierman May 1, 2026
9debcc5
chore: update bun.lock after adding magic-regexp
andrew-bierman May 1, 2026
e891d57
docs: mark better-auth migration plan as completed
andrew-bierman May 1, 2026
6395c2e
refactor(auth): remove legacy JWT/token utilities and empty auth routes
andrew-bierman May 1, 2026
eb0bf68
test(auth): add comprehensive Better Auth integration tests
andrew-bierman May 1, 2026
9c4fe24
chore: remove stale nativewindui@1.1.0 patch
andrew-bierman May 1, 2026
d385b45
fix(db): split UUID+Better Auth migration into 6 working parts
mikib0 May 2, 2026
23f7ed0
fix(db): handle social feed tables in UUID migration 0045
mikib0 May 2, 2026
40b14f9
chore: update lockfile
mikib0 May 2, 2026
d7a4ef2
chore(api/auth): add static auth.config.ts stub for Better Auth CLI i…
mikib0 May 2, 2026
7409b3a
fix(api/db): add missing required better-auth fields
mikib0 May 2, 2026
02b9610
fix(api/better-auth): add missing jwks table to adapter schema config…
mikib0 May 2, 2026
d40e856
fix(api/auth): handle pre-migration bcrypt password hashes in Better …
mikib0 May 2, 2026
2352804
chore(api/tests): fix failing API tests caused by a missing `name` field
mikib0 May 2, 2026
0fd4bdf
fix(api/schemas): update userId and timestamp field types after UUID …
mikib0 May 3, 2026
8b9732e
fix(expo/auth): avoid logout on network failure
mikib0 May 3, 2026
e6c62ed
fix(api/auth): add expo server plugin to fix sign-out 403
mikib0 May 3, 2026
ce8d0f0
fix(expo/auth): annotate safe-casts to pass pre-push strict check
mikib0 May 3, 2026
d92d7c3
chore(expo): add expo-network dependency
mikib0 May 3, 2026
e2f1b8f
Merge remote-tracking branch 'origin/development' into feat/better-au…
mikib0 May 3, 2026
490b9a0
fix(api/db): make uuid migration resilient to missing social feed tables
mikib0 May 3, 2026
a9e92f2
fix(expo/auth): restore guest mode and reactive isAuthed sync
mikib0 May 3, 2026
bcb4221
fix(expo/auth): post-sign-out prompt, clear RQ cache, fix sign-in hang
mikib0 May 3, 2026
8108a15
fix(api/auth): register Apple provider for native id-token flow
mikib0 May 4, 2026
da32d86
fix(lint): resolve biome warnings for code quality
Copilot May 4, 2026
18566c5
fix(api): remove deleted/lastActiveAt fields from users table after B…
Copilot May 4, 2026
d9357df
fix(lint): remove unused variables and imports after Better Auth migr…
Copilot May 4, 2026
ce0496e
fix(types): remove lastActiveAt/deletedAt references and fix user id …
Copilot May 4, 2026
c557aeb
merge: resolve conflicts with development
andrew-bierman May 7, 2026
8ed5595
fix(merge): repair post-merge type breakage from development conflicts
andrew-bierman May 7, 2026
0605558
chore(merge): reconcile bun.lock with deps from development merge
andrew-bierman May 7, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions apps/expo/app/(app)/ai-chat.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@ import { LocationContext } from 'expo-app/features/ai/components/LocationContext
import { CustomChatTransport } from 'expo-app/features/ai/lib/CustomChatTransport';
import { getLocalModel, initLocalModel } from 'expo-app/features/ai/lib/localModelManager';
import { createLocalTools } from 'expo-app/features/ai/lib/tools';
import { tokenAtom } from 'expo-app/features/auth/atoms/authAtoms';
import { useActiveLocation } from 'expo-app/features/weather/hooks';
import type { WeatherLocation } from 'expo-app/features/weather/types';
import { authClient } from 'expo-app/lib/auth-client';
import { useColorScheme } from 'expo-app/lib/hooks/useColorScheme';
import { useTranslation } from 'expo-app/lib/hooks/useTranslation';
import { getContextualGreeting, getContextualSuggestions } from 'expo-app/utils/chatContextHelpers';
Expand Down Expand Up @@ -90,7 +90,8 @@ export default function AIChat() {
const locationRef = React.useRef(context.location);
locationRef.current = context.location;

const token = useAtomValue(tokenAtom);
const { data: _authSession } = authClient.useSession();
const token = _authSession?.session?.token ?? null;
Comment on lines +93 to +94

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Don't send Authorization: Bearer null.

When the session is still loading or the user is signed out, this builds a bogus bearer credential for every remote chat request. Omit the header until a real token exists.

Suggested fix
-  const token = _authSession?.session?.token ?? null;
+  const token = _authSession?.session?.token;-      headers: {
-        Authorization: `Bearer ${token}`,
-      },
+      headers: token
+        ? {
+            Authorization: `Bearer ${token}`,
+          }
+        : {},

Also applies to: 136-138

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/expo/app/`(app)/ai-chat.tsx around lines 93 - 94, The code currently
builds a token variable from authClient.useSession() and may send
"Authorization: Bearer null" when no session exists; change the request header
construction so the Authorization header is only added when token is a
non-null/non-undefined string (i.e. check _authSession?.session?.token
truthiness before adding the header). Update places referencing the token (the
token const and the remote chat request headers around the fetch/axios calls at
lines ~136-138) to conditionally include Authorization and omit the header
entirely when token is null.

const [input, setInput] = React.useState('');
const [lastUserMessage, setLastUserMessage] = React.useState('');
const [previousMessages, setPreviousMessages] = React.useState<UIMessage[]>([]);
Expand Down
2 changes: 1 addition & 1 deletion apps/expo/app/(app)/feed/[id].tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { ActivityIndicator, View } from 'react-native';

export default function PostDetailRoute() {
const { id } = useLocalSearchParams<{ id: string }>();
const currentUserId = userStore.id.peek() as number | undefined;
const currentUserId = userStore.id.peek() as string | undefined;

const { data: post, isLoading } = useQuery({
queryKey: ['feed', Number(id)],
Expand Down
2 changes: 1 addition & 1 deletion apps/expo/app/auth/(login)/reset-password.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ export default function ResetPasswordScreen() {
setIsLoading(true);

// Call the API to reset the password
await resetPassword(params.email, { code: params.code, newPassword: value.password });
await resetPassword(params.email, { token: params.code, newPassword: value.password });

// Show success message and navigate to login
Alert.alert(t('common.success'), t('auth.resetPasswordSuccess'), [
Expand Down
34 changes: 0 additions & 34 deletions apps/expo/features/auth/atoms/authAtoms.ts
Original file line number Diff line number Diff line change
@@ -1,39 +1,5 @@
import Storage from 'expo-sqlite/kv-store';
import { atom } from 'jotai';
import { atomWithStorage } from 'jotai/utils';

// User type definition
export type User = {
id: number;
email: string;
firstName?: string;
lastName?: string;
emailVerified: boolean;
};

// Token storage atom
export const tokenAtom = atomWithStorage<string | null>('access_token', null, {
getItem: (key) => Storage.getItemSync(key),
setItem: (key, value) => {
if (value === null) return Storage.removeItemSync(key);
return Storage.setItemSync(key, value);
},
removeItem: (key) => Storage.removeItemSync(key),
});

export const refreshTokenAtom = atomWithStorage<string | null>('refresh_token', null, {
getItem: (key) => Storage.getItemSync(key),
setItem: (key, value) => {
if (value === null) return Storage.removeItemSync(key);
return Storage.setItemSync(key, value);
},
removeItem: (key) => Storage.removeItemSync(key),
});

// Loading state atom
export const isLoadingAtom = atom(false);

export const redirectToAtom = atom<string>('/');

// Re-authentication state
export const needsReauthAtom = atom(false);
Loading
Loading