Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
7 changes: 6 additions & 1 deletion apps/swift/Resources/PackRat-iOS.entitlements
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict/>
<dict>
<key>com.apple.developer.applesignin</key>
<array>
<string>Default</string>
</array>
</dict>
</plist>
2 changes: 2 additions & 0 deletions packages/api/.dev.vars.e2e.example
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ PACKRAT_GUIDES_BASE_URL=https://guides.packratai.com/
EXPO_PUBLIC_GOOGLE_IOS_CLIENT_ID=<your-google-ios-client-id>
EXPO_PUBLIC_GOOGLE_WEB_CLIENT_ID=<your-google-web-client-id>
GOOGLE_CLIENT_ID=<your-google-client-id>
GOOGLE_IOS_CLIENT_ID=<your-google-ios-client-id>
GOOGLE_CLIENT_SECRET=<your-google-client-secret>

# ── Maps ─────────────────────────────────────────────────────────────────────
Expand All @@ -68,6 +69,7 @@ SENTRY_DSN=<your-sentry-dsn>

# ── Apple Sign In ─────────────────────────────────────────────────────────────
APPLE_CLIENT_ID=<your-apple-client-id>
APPLE_SWIFT_CLIENT_ID=<your-apple-swift-client-id>
APPLE_PRIVATE_KEY=<your-apple-private-key>
APPLE_KEY_ID=<your-apple-key-id>
APPLE_TEAM_ID=<your-apple-team-id>
11 changes: 9 additions & 2 deletions packages/api/src/auth/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -193,15 +193,21 @@ async function buildAuth(env: ValidatedEnv): Promise<any> {

socialProviders: {
google: {
clientId: env.GOOGLE_CLIENT_ID ?? '',
// iOS native Google Sign-In requests an id token whose `aud` claim is the
// iOS OAuth client ID, distinct from the web client ID β€” accept both audiences.
clientId: [env.GOOGLE_CLIENT_ID, env.GOOGLE_IOS_CLIENT_ID].filter((id): id is string =>
Boolean(id),
),
clientSecret: env.GOOGLE_CLIENT_SECRET ?? '',
},
// Always register Apple when clientId is present so the native id-token
// flow works even without a valid client-secret JWT (the id-token path
// verifies against Apple's public JWKS; the secret is only used for the
// web OAuth redirect flow).
// audience covers all EAS build variants β€” Apple puts the bundle ID in
// the `aud` claim, which differs per variant (.dev, .preview, base).
// the `aud` claim, which differs per variant (.dev, .preview, base) β€” plus
// the native Swift app's distinct bundle ID, which is a separate Xcode
// target and not an EAS build variant of the Expo app.
...(env.APPLE_CLIENT_ID
? {
apple: {
Expand All @@ -212,6 +218,7 @@ async function buildAuth(env: ValidatedEnv): Promise<any> {
env.APPLE_CLIENT_ID,
`${env.APPLE_CLIENT_ID}.dev`,
`${env.APPLE_CLIENT_ID}.preview`,
...(env.APPLE_SWIFT_CLIENT_ID ? [env.APPLE_SWIFT_CLIENT_ID] : []),
],
},
}
Expand Down
6 changes: 6 additions & 0 deletions packages/api/src/utils/env-validation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,15 @@ export const apiEnvObjectSchema = z.object({
E2E_TEST_USER_ID: z.string().uuid().optional(),
// Google OAuth (Better Auth social provider)
GOOGLE_CLIENT_ID: z.string(),
// iOS native Google Sign-In uses a separate OAuth client whose ID appears in the
// ID token's `aud` claim β€” Better Auth must accept both audiences or native sign-in fails.
GOOGLE_IOS_CLIENT_ID: z.string().optional(),
GOOGLE_CLIENT_SECRET: z.string(),
// Apple Sign In (Better Auth social provider)
APPLE_CLIENT_ID: z.string(), // bundle ID e.g. world.packrat.app
// Native Swift app's distinct bundle ID (separate Xcode target, not an EAS build
// variant of the Expo app) β€” appears in its Apple ID token's `aud` claim.
APPLE_SWIFT_CLIENT_ID: z.string().optional(),
APPLE_PRIVATE_KEY: z.string(), // .p8 key contents β€” store via wrangler secret
APPLE_KEY_ID: z.string(),
APPLE_TEAM_ID: z.string(),
Expand Down
Loading