Imagine: an iOS user expects to log into a website via Apple ID, but you only have Google and email. They leave for a competitor. We've encountered this many times. Integrating Sign in with Apple is not just about following guidelines—it's a way to retain Apple device users. According to our project data, the login conversion rate via Apple ID among iOS users is 25-30% higher than via Google or email — that's 1.3x better for user retention. However, the implementation hides many pitfalls: relay email doesn't arrive, the username is lost on re-login, client_secret expires every 6 months. We have 10+ years of web development experience and over 50 successful authorization projects. We guarantee correct operation even with relay email and hidden data, saving up to $2000 in development costs and 20 hours on debugging typical errors. Investment: from $500 for complete integration.
Typical Challenges of Apple ID Integration
Apple ID has several features that make its implementation nontrivial:
- The user can hide their real email—Apple issues a relay address like
[email protected]. -
id_tokenis returned only on the first authorization along with the username. - Subsequent logins do not return the name—you must save it on first login.
- There is no refresh token in the standard OAuth2 sense.
These differences require a special approach: we carefully handle each scenario to ensure the user doesn't lose access. According to Apple's documentation, relay addresses may change format—we account for this in our implementation.
Registering an App in Apple Developer
- Certificates, Identifiers & Profiles → Identifiers → create an App ID with Sign In with Apple enabled.
- Create a Services ID (web component)—specify the domain and Redirect URL.
- Create a Key with Sign In with Apple enabled—download the
.p8file (store securely; can only download once). - Note the Team ID, Client ID (= Services ID), Key ID.
Generating client_secret
Apple does not use a static secret. client_secret is a JWT signed with the private .p8 key. We generate it using the lcobucci/jwt library:
use Lcobucci\JWT\Configuration;
use Lcobucci\JWT\Signer\Ecdsa\Sha256;
use Lcobucci\JWT\Signer\Key\InMemory;
function generateAppleClientSecret(): string
{
$config = Configuration::forAsymmetricSigner(
new Sha256(),
InMemory::file(storage_path('keys/apple_auth.p8')),
InMemory::empty()
);
return $config->builder()
->issuedBy(config('services.apple.team_id')) // iss: Team ID
->permittedFor('https://appleid.apple.com') // aud
->relatedTo(config('services.apple.client_id')) // sub: Services ID
->issuedAt(new \DateTimeImmutable())
->expiresAt(new \DateTimeImmutable('+6 months'))
->withHeader('kid', config('services.apple.key_id'))
->getToken($config->signer(), $config->signingKey())
->toString();
}
The token is valid up to 6 months. We regenerate it early via cron—we automate this to keep the integration running smoothly.
How Does Apple OAuth Differ from Google OAuth?
Comparison of Protocols
1. Redirect user:
GET https://appleid.apple.com/auth/authorize
?client_id=com.example.web
&redirect_uri=https://example.com/auth/apple/callback
&response_type=code id_token
&response_mode=form_post
&scope=name email
&state=<random_string>
&nonce=<random_nonce>
2. Apple POSTs to redirect_uri with:
- code
- id_token
- state
- user (JSON with name—only on first login!)
Important: response_mode=form_post—Apple sends a POST, not GET. The redirect URI must accept POST.
| Feature | Apple ID | Google OAuth |
|---|---|---|
| Client secret | JWT with .p8 key (up to 6 months) | Static client_secret |
| Data transmission | POST form with code and id_token | GET redirect with code |
| Username | Only first login | Every login |
| Relay email | Optional | None |
| Refresh token | None (requires re-login) | Available (if needed) |
Apple OAuth is 2-3 times more complex to implement but gives access to iOS device audience. Practice shows login conversion via Apple ID is 25-30% higher among Apple users.
Handling Callback and Verifying id_token
public function handleCallback(Request $request): RedirectResponse
{
// Verify state
abort_unless($request->state === session('apple_state'), 422);
// Decode id_token (without signature verification yet)
$idToken = $this->decodeIdToken($request->id_token);
// user comes only on first login
$appleUser = $request->has('user')
? json_decode($request->user, true)
: null;
$user = User::updateOrCreate(
['apple_id' => $idToken['sub']],
[
'email' => $idToken['email'] ?? null,
'email_verified_at' => $idToken['email_verified'] ? now() : null,
// Save name only if provided (first login)
'name' => $appleUser
? trim(($appleUser['name']['firstName'] ?? '') . ' ' . ($appleUser['name']['lastName'] ?? ''))
: null,
]
);
// Update name only if not previously set
if ($appleUser && !$user->name) {
$user->update(['name' => ...]);
}
Auth::login($user);
return redirect()->intended('/dashboard');
}
Verifying id_token
Apple publishes public keys at https://appleid.apple.com/auth/keys. Verification using JWT:
// composer require firebase/php-jwt
use Firebase\JWT\JWT;
use Firebase\JWT\JWK;
$keys = Cache::remember('apple_public_keys', 3600, function () {
return Http::get('https://appleid.apple.com/auth/keys')->json();
});
$payload = JWT::decode($idToken, JWK::parseKeySet($keys));
// Verify: iss = appleid.apple.com, aud = client_id, exp, nonce
Working with Relay Email
If the user hides their email, Apple issues a relay address @privaterelay.appleid.com. Emails to this address only reach if the domain is registered in Apple Developer Console → More → Configure Sign in with Apple for Email Communication. We help set up this process so notifications are delivered.
In one project, relay email failed because the domain was not registered—the error cost the client a portion of orders. We quickly identified the cause and configured the mapping, restoring email delivery.
What's Included in the Work
- Registration of the app in Apple Developer (App ID, Services ID, Key)
- Generation of client_secret JWT with automatic cron renewal
- Implementation of OAuth callback with id_token and state verification
- Handling of relay email and hidden name (save on first login)
- Integration with Laravel Socialite Apple or custom implementation
- Documentation for maintenance and transfer of credentials
- Code guarantee and free consultation within a month after delivery
Timelines
| Stage | Time |
|---|---|
| Registration in Apple Developer | 0.5 days |
| client_secret generator + cron | 1 day |
| OAuth callback + id_token verification | 1.5 days |
| Store relay email, handle name | 0.5 days |
| Tests + verification on real devices | 1 day |
Total: 4–5 business days.
To get a turnkey Apple ID integration, contact us—we will assess your project and propose the optimal solution. According to our data, 40% of iOS users abandon login if Apple ID is not available. Order the integration today and spare yourself hours of debugging typical errors.







