APNs JWT generator (.p8 provider token)
Sign an APNs provider token from your .p8 key, Key ID and Team ID, see when it expires, and copy a ready curl request. Signing happens in this tab, and this tool's code doesn't send the key anywhere.
- ES256 with Web Crypto
- Free, no sign-up
Your key is read and used for signing inside this browser tab. This tool's code does not send it anywhere, and doesn't save it: once loaded it is held in memory, hidden from the screen, and gone when you reload or press Clear key.
No key loaded.
Add your key, Key ID and Team ID, then press Generate token.
Decoded header and claims
Test request
com.example.app is an example value: replace it with your bundle ID.
Free to use, no account. More push tools
How the token is built
APNs token authentication uses a JSON Web Token signed with your team's .p8 key. The header has two fields, {"alg": "ES256", "kid": "<Key ID>"}, and the claims have two more, {"iss": "<Team ID>", "iat": <seconds since 1970>}. Each part is JSON, base64url-encoded without padding, and the two are joined with a dot. That string is signed with ECDSA on the P-256 curve with SHA-256 (ES256), and the signature, also base64url, becomes the third part. You send the result in every request as authorization: bearer <token>.
This page signs in the tab with a non-extractable Web Crypto key and shows the decoded parts, so you can compare them with your server's token.
The signature format gotcha
A JWS ES256 signature is exactly 64 bytes: r, then s, 32 bytes each. OpenSSL, Java's Signature and many older helpers return DER instead, an ASN.1 sequence usually 70 to 72 bytes long, and APNs rejects it with 403 InvalidProviderToken. If your server's tokens are longer than this page's, convert the DER signature to raw r||s, left-padding each integer to 32 bytes.
The 20 and 60 minute rules
- APNs rejects a token whose
iatis over an hour old with403 ExpiredProviderToken; the countdown above shows the time left. - Refresh no more than once every 20 minutes, or APNs can return
429 TooManyProviderTokenUpdates. Cache one token per key and replace it between minute 20 and minute 60. - Use the server clock in UTC: a clock that runs ahead or behind skews
iat. - Set 61 min ago builds an already expired token, to test how your server handles the 403.
Where the IDs come from
- Key ID: under Certificates, Identifiers & Profiles > Keys, and in the file name
AuthKey_ABC123DEFG.p8, which this page reads when it can. - Team ID: in the Membership details of your developer account, 10 characters. It is the
issclaim, not the bundle ID. - apns-topic: your bundle ID, for example
com.example.app. The token is not tied to one app, so the topic header decides which app gets the push.
Checking the result
Copy the curl command, set DEVICE_TOKEN to a token from a build signed for the same environment, and run it. A 200 means APNs accepted the push; any other status comes with a reason, which the APNs error codes page explains. The device token checker catches malformed tokens, and the push notification tester builds the payload.
Questions
How long is an APNs JWT valid?
Up to one hour from its iat time. After that APNs returns 403 ExpiredProviderToken. Apple also asks you not to refresh more than once every 20 minutes; a new token on the same connection sooner than that can get 429 TooManyProviderTokenUpdates. Refresh between 20 and 60 minutes.
Is my .p8 key uploaded?
No. Your key is read and used for signing inside this browser tab, with the Web Crypto API. This tool's code does not send it anywhere and does not store it. For production, sign tokens on your server and keep the key in a secret store.
What is the difference between InvalidProviderToken and ExpiredProviderToken?
ExpiredProviderToken (403) means the signature checked out but iat is more than an hour old: make a new token. InvalidProviderToken (403) means APNs could not verify the token: a wrong Key ID or Team ID, a revoked key, a DER signature instead of raw r||s, or a token built with the wrong algorithm.
Should I use token auth or certificate auth?
Token auth is simpler to run: one .p8 key works for all apps in your team, for sandbox and production, and it does not expire the way a push certificate does. Certificate auth still works and suits tools that read a certificate from the Keychain.
Can one key serve all my apps?
Yes. A team-scoped APNs key signs tokens for every app in the team, in both environments. The token only names the team (iss) and key (kid); the apns-topic header picks the app on each request. Apple also offers keys limited to one topic or environment; those only work for that scope.
From the same developer
- Push Notification Tester: send APNs test pushes from your Mac.
- The sending side of APNs.

