From 029cbdc072afa32201319efff3be19792d275e8a Mon Sep 17 00:00:00 2001 From: ZerGo0 <18653821+ZerGo0@users.noreply.github.com> Date: Fri, 12 Jun 2026 02:54:44 +0200 Subject: [PATCH] docs: update Apple client secret JWT guidance (#9938) --- docs/app/docs/[[...slug]]/page.tsx | 2 -- docs/components/docs/mdx-components.tsx | 10 ---------- docs/content/docs/authentication/apple.mdx | 20 ++++++++++++-------- 3 files changed, 12 insertions(+), 20 deletions(-) diff --git a/docs/app/docs/[[...slug]]/page.tsx b/docs/app/docs/[[...slug]]/page.tsx index 64af454ec1..b68b80df96 100644 --- a/docs/app/docs/[[...slug]]/page.tsx +++ b/docs/app/docs/[[...slug]]/page.tsx @@ -21,7 +21,6 @@ import { DividerText, Endpoint, ForkButton, - GenerateAppleJwt, GenerateSecret, } from "@/components/docs/mdx-components"; import { Callout } from "@/components/ui/callout"; @@ -115,7 +114,6 @@ export default async function Page({ AddToCursor, Features, Endpoint, - GenerateAppleJwt, GenerateSecret, DividerText, Callout: ({ diff --git a/docs/components/docs/mdx-components.tsx b/docs/components/docs/mdx-components.tsx index 4e090a721d..31764b45c5 100644 --- a/docs/components/docs/mdx-components.tsx +++ b/docs/components/docs/mdx-components.tsx @@ -613,16 +613,6 @@ export function DividerText({ children }: { children: ReactNode }) { ); } -// ─── GenerateAppleJwt ──────────────────────────────────────────────────────── - -export function GenerateAppleJwt() { - return ( -
- See the Apple documentation for generating a client secret JWT. -
- ); -} - // ─── Features (placeholder) ───────────────────────────────────────────────── export function Features({ stars }: { stars?: string | null }) { diff --git a/docs/content/docs/authentication/apple.mdx b/docs/content/docs/authentication/apple.mdx index 5315ac3d9e..97931aa687 100644 --- a/docs/content/docs/authentication/apple.mdx +++ b/docs/content/docs/authentication/apple.mdx @@ -7,7 +7,7 @@ description: Apple provider setup and usage. ### Get your OAuth credentials - To use Apple sign in, you need a client ID and client secret. You can get them from the [Apple Developer Portal](https://developer.apple.com/account/resources/authkeys/list). + To use Apple sign in, you need a client ID, Team ID, Key ID, and private key. You can get them from the [Apple Developer Portal](https://developer.apple.com/account/resources/authkeys/list), then use them to generate the client secret JWT. You will need an active **Apple Developer account** to access the developer portal and generate these credentials. @@ -56,17 +56,17 @@ description: Apple provider setup and usage. 6. **Generate the Client Secret (JWT):** Apple requires a JSON Web Token (JWT) to be generated dynamically using the downloaded `.p8` key, the Key ID, and your Team ID. This JWT serves as your `clientSecret`. - You can use the guide below from [Apple's documentation](https://developer.apple.com/documentation/accountorganizationaldatasharing/creating-a-client-secret) to understand how to generate this client secret. You can also use our built in generator [below](#generate-apple-client-secret-jwt) to generate the client secret JWT required for 'Sign in with Apple'. + We recommend generating the client secret JWT in your auth configuration using the [`jose` example below](#configure-the-provider). You can also generate it manually by following [Apple's documentation](https://developer.apple.com/documentation/accountorganizationaldatasharing/creating-a-client-secret), then pass the generated JWT as `clientSecret`. - **Note:** Apple allows a maximum expiration of 6 months (180 days) for the client secret JWT. You will need to regenerate the client secret before it expires to maintain uninterrupted authentication. + **Note:** Apple rejects client secret JWTs that expire more than 15,777,000 seconds (six months) in the future. You will need to regenerate the client secret before it expires to maintain uninterrupted authentication. - Apple's OAuth implementation requires a JWT (JSON Web Token) as the `clientSecret` instead of a static secret string. + Apple's OAuth implementation requires a JWT (JSON Web Token) as the `clientSecret` instead of a shared secret string. According to [Apple's documentation](https://developer.apple.com/documentation/accountorganizationaldatasharing/creating-a-client-secret), these JWTs: - * Have a maximum expiration of 6 months + * Can't expire more than 15,777,000 seconds (six months) in the future * Must be cryptographically signed with your private key Install `jose` package to generate the client secret JWT. @@ -103,7 +103,7 @@ description: Apple provider setup and usage. export const auth = betterAuth({ socialProviders: { - apple: { // [!code highlight] + apple: async () => ({ // [!code highlight] clientId: process.env.APPLE_CLIENT_ID as string, // [!code highlight] clientSecret: await generateAppleClientSecret( process.env.APPLE_CLIENT_ID!, // [!code highlight] @@ -113,7 +113,7 @@ description: Apple provider setup and usage. ), // [!code highlight] // Optional appBundleIdentifier: process.env.APPLE_APP_BUNDLE_IDENTIFIER as string, // [!code highlight] - }, // [!code highlight] + }), // [!code highlight] }, // Add appleid.apple.com to trustedOrigins for Sign In with Apple flows trustedOrigins: ["https://appleid.apple.com"], // [!code highlight] @@ -181,4 +181,8 @@ await authClient.signIn.social({ ## Generate Apple Client Secret (JWT) - +If you previously used the in-page generator from this section, use the [`jose` example above](#configure-the-provider) instead. It uses Better Auth's async provider configuration to generate the Apple client secret JWT from your Client ID, Team ID, Key ID, and private key. + +The example uses a 180-day expiration, which stays below Apple's six-month limit. Generating the token from configuration avoids copying a static generated token into your auth setup. + +Alternatively, you can still generate the client secret JWT manually by following [Apple's documentation](https://developer.apple.com/documentation/accountorganizationaldatasharing/creating-a-client-secret), then pass the generated JWT as `clientSecret`. If you choose this approach, remember to replace it before it expires.