diff --git a/docs/content/docs/authentication/apple.mdx b/docs/content/docs/authentication/apple.mdx index 9d192ba65a..0ca9b6baaa 100644 --- a/docs/content/docs/authentication/apple.mdx +++ b/docs/content/docs/authentication/apple.mdx @@ -25,10 +25,14 @@ description: Apple provider setup and usage. apple: { // [!code highlight] clientId: process.env.APPLE_CLIENT_ID as string, // [!code highlight] clientSecret: process.env.APPLE_CLIENT_SECRET as string, // [!code highlight] + // Optional + appBundleIdentifier: process.env.APPLE_APP_BUNDLE_IDENTIFIER as string, // [!code highlight] }, // [!code highlight] }, }) ``` + + On native iOS, it doesn't use the service id but the app id (bundle id) as client id, so if using the service id as clientId in signIn.social() with idToken, it throws an error: JWTClaimValidationFailed: unexpected "aud" claim value. So you need to provide the appBundleIdentifier when you want to sign in with Apple using the ID Token. diff --git a/packages/better-auth/src/social-providers/apple.ts b/packages/better-auth/src/social-providers/apple.ts index 41cbc1b9a8..93b291db64 100644 --- a/packages/better-auth/src/social-providers/apple.ts +++ b/packages/better-auth/src/social-providers/apple.ts @@ -64,7 +64,9 @@ export interface AppleNonConformUser { email: string; } -export interface AppleOptions extends ProviderOptions {} +export interface AppleOptions extends ProviderOptions { + appBundleIdentifier?: string; +} export const apple = (options: AppleOptions) => { const tokenEndpoint = "https://appleid.apple.com/auth/token"; @@ -105,7 +107,7 @@ export const apple = (options: AppleOptions) => { const { payload: jwtClaims } = await jwtVerify(token, publicKey, { algorithms: [jwtAlg], issuer: "https://appleid.apple.com", - audience: options.clientId, + audience: options.appBundleIdentifier || options.clientId, maxTokenAge: "1h", }); ["email_verified", "is_private_email"].forEach((field) => { @@ -125,7 +127,7 @@ export const apple = (options: AppleOptions) => { if (!token.idToken) { return null; } - const profile = decodeJwt(token.idToken)?.payload as AppleProfile | null; + const profile = decodeJwt(token.idToken); if (!profile) { return null; }