oskar.makarov
portfolio / apple secret · troubleshooting
troubleshooting · sign in with apple

Sign in with Apple broke with invalid_client

It worked for months, nothing was deployed, and suddenly nobody can log in. If your Apple sign-in is about six months old, this is almost certainly your case.

What it looks like

Apple's token endpoint stops accepting your app and answers with a short JSON error. Nothing changed on your side:

HTTP 400 · https://appleid.apple.com/auth/token
{"error":"invalid_client"}

Users see something else: the Apple button does nothing, or drops them back on the login screen with no message. Your logs show the same invalid_client.

Why it happens

Unlike every other OAuth provider, Apple has no long-lived client secret. What you pasted into your backend or into Supabase is a JWT you signed yourself, and Apple caps its lifetime at roughly six months: 15777000 seconds is the documented maximum.

Apple sends no expiry warning. No email, no console banner, no dashboard flag. The secret simply stops being valid, and the first people to find out are your users.

The official Supabase documentation openly recommends setting a recurring calendar reminder every six months. That is the current state of the art.

Confirm it's this and not something else

Your client secret is a JWT: three base64 chunks separated by dots. Decode the middle one and look at the exp claim, a Unix timestamp.

  1. Take the secret from your backend config or from the Apple provider settings in Supabase
  2. Decode the payload: any JWT decoder, or base64 on the middle segment
  3. exp in the past means this is your case. exp in the future means something else: wrong Services ID, wrong Team ID, or a redirect URI mismatch.

What Apple expects inside that JWT

Useful when you rebuild the secret by hand: a wrong claim returns exactly the same invalid_client, which is what makes this error so hard to diagnose.

algES256, Apple accepts nothing else
kidKey ID of your .p8 key
issyour Apple Team ID
subthe Services ID, not your app bundle ID
audhttps://appleid.apple.com
expno further than iat + 15777000 seconds

Fix it right now, by hand

  1. Open the Apple Developer portal → Certificates, Identifiers & Profiles → Keys and find the key you created for Sign in with Apple. You need its Key ID and the .p8 file. If the .p8 is lost, create a new key: Apple lets you download that file only once.
  2. Your Team ID is in the top-right corner of the portal. Your Services ID is under Identifiers, it looks like a reversed domain, and it is not your app's bundle ID.
  3. Build a fresh JWT signed with ES256 and the claims from the table above. Set exp no further than six months out.
  4. Paste the new secret where the old one lived: your backend config, or Supabase → Authentication → Providers → Apple → Secret Key.
  5. Sign in once to confirm. The error clears immediately, there is nothing to propagate and no cache to purge.

That's the entire fix. It takes about ten minutes and buys you six months.

It will happen again

In about six months, the same thing: the same silence from Apple, the same confused users. A calendar reminder works right up until the day someone is on holiday, changed jobs, or simply swiped the notification away.

Or stop doing it by hand

I hit this on my own project and wrote a free GitHub Action for it. On a schedule it rebuilds the JWT from your .p8 and writes it into Supabase through the Management API. Not on Supabase? It hands the fresh secret back as an output, pipe it wherever you need. MIT, zero dependencies, the whole logic is one readable file.

Open the tool → free · MIT · runs every 5 months, a month of margin

FAQ

Can I just set a longer expiry and forget it?

No. Six months is Apple's hard ceiling. A JWT with a longer exp is rejected outright, so you get the same invalid_client immediately instead of in half a year.

Does regenerating the secret log everyone out?

No. The client secret authenticates your server to Apple, not your users to you. Existing sessions are untouched.

I lost the .p8 file. Is that fatal?

No, but it can't be recovered: Apple allows a single download. Create a new key in the portal, note its new Key ID, and rebuild the secret with the new pair.

Why does invalid_client also show up on a fresh secret?

Because Apple returns the same error for several different mistakes: a bundle ID instead of the Services ID in sub, the wrong Team ID in iss, an algorithm other than ES256, or a redirect URI that doesn't match the registered one. That's why checking exp first is worth it, it rules out half the branches immediately.

Set it once.
Forget it.

Get it on GitHub Marketplace → free · MIT · zero dependencies · set up once
© 2026 Oskar Makarov ▍apple-client-secret-rotator · MIT