diff --git a/server/src/services/passkey.service.spec.ts b/server/src/services/passkey.service.spec.ts index 37bb23af2..4ebabda70 100644 --- a/server/src/services/passkey.service.spec.ts +++ b/server/src/services/passkey.service.spec.ts @@ -308,7 +308,7 @@ describe(PasskeyService.name, () => { expect(mocks.passkey.create).not.toHaveBeenCalled(); }); - it('should verify against the android app origins when the origin header is missing', async () => { + it('should verify against the mobile app origins when the origin header is missing', async () => { const auth = AuthFactory.from().session().build(); const passkey = PasskeyFactory.create({ userId: auth.user.id }); @@ -323,6 +323,7 @@ describe(PasskeyService.name, () => { expect(mocks.webAuthn.verifyRegistrationResponse).toHaveBeenCalledWith( expect.objectContaining({ expectedOrigin: [ + 'https://my.immich.app', 'android:apk-key-hash:hsXEVd-vSYWSOo81rbMdDJ4LlX1_lMLSr2okOKqWACA', 'android:apk-key-hash:WiLBg0dUBfVJxOufsmwuk6PvnFdmFQp684yNP-UVzNY', ], diff --git a/server/src/services/passkey.service.ts b/server/src/services/passkey.service.ts index 3499c85e6..5392931db 100644 --- a/server/src/services/passkey.service.ts +++ b/server/src/services/passkey.service.ts @@ -32,6 +32,9 @@ const CHALLENGE_TTL = Duration.fromObject({ minutes: 5 }); const MOBILE_RP_ID = 'my.immich.app'; +// iOS apps send https:// + the rp id as their origin +const IOS_ORIGIN = `https://${MOBILE_RP_ID}`; + // keep in sync with https://my.immich.app/.well-known/assetlinks.json const ANDROID_CERTIFICATE_FINGERPRINTS = [ '86:C5:C4:55:DF:AF:49:85:92:3A:8F:35:AD:B3:1D:0C:9E:0B:95:7D:7F:94:C2:D2:AF:6A:24:38:AA:96:00:20', @@ -273,7 +276,7 @@ export class PasskeyService extends BaseService { const origin = headers.origin; // no origin implies a mobile app if (!origin) { - return { origin: ANDROID_ORIGINS, rpId: MOBILE_RP_ID }; + return { origin: [IOS_ORIGIN, ...ANDROID_ORIGINS], rpId: MOBILE_RP_ID }; } let hostname: string;