Apple ID Authentication for Website

Our company is engaged in the development, support and maintenance of sites of any complexity. From simple one-page sites to large-scale cluster systems built on micro services. Experience of developers is confirmed by certificates from vendors.
Development and maintenance of all types of websites:
Informational websites or web applications
Business card websites, landing pages, corporate websites, online catalogs, quizzes, promo websites, blogs, news resources, informational portals, forums, aggregators
E-commerce websites or web applications
Online stores, B2B portals, marketplaces, online exchanges, cashback websites, exchanges, dropshipping platforms, product parsers
Business process management web applications
CRM systems, ERP systems, corporate portals, production management systems, information parsers
Electronic service websites or web applications
Classified ads platforms, online schools, online cinemas, website builders, portals for electronic services, video hosting platforms, thematic portals

These are just some of the technical types of websites we work with, and each of them can have its own specific features and functionality, as well as be customized to meet the specific needs and goals of the client.

Our competencies:
Development stages
Latest works
  • image_website-b2b-advance_0.png
    B2B ADVANCE company website development
    1212
  • image_web-applications_feedme_466_0.webp
    Development of a web application for FEEDME
    1161
  • image_websites_belfingroup_462_0.webp
    Website development for BELFINGROUP
    852
  • image_ecommerce_furnoro_435_0.webp
    Development of an online store for the company FURNORO
    1041
  • image_crm_enviok_479_0.webp
    Development of a web application for Enviok
    822
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Website development for FIXPER company
    815

Sign in with Apple Implementation for Websites

Sign in with Apple is required by Apple for native iOS/macOS apps: if an app offers any social authorization, Apple ID must be present. For web it's not formally mandatory, but needed where the audience is Apple device users and for web components of iOS-based apps.

Apple ID has unique features compared to Google OAuth and other providers:

  • User can hide their real email—Apple issues a relay address like [email protected]
  • id_token returns only on first auth with user name
  • Subsequent logins don't return name—must save on first login
  • No refresh token in standard OAuth2 sense

Registering App in Apple Developer

  1. Certificates, Identifiers & ProfilesIdentifiers → create App ID with Sign In with Apple enabled
  2. Create Services ID (web component)—specify domain and Redirect URL
  3. Create Key with Sign In with Apple enabled—download .p8 file (store securely, can download only once)
  4. Note: Team ID, Client ID (= Services ID), Key ID

Generating client_secret

Apple doesn't use static secrets. client_secret is a JWT signed with the private .p8 key:

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();
}

Expires up to 6 months. Recreate token in advance via cron.

OAuth2 Flow

1. User redirect:
   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 does POST, not GET. Redirect URI must accept POST.

Callback Handling

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 received (first login)
            'name' => $appleUser
                ? trim(($appleUser['name']['firstName'] ?? '') . ' ' . ($appleUser['name']['lastName'] ?? ''))
                : null,
        ]
    );

    // Update name only if not set before
    if ($appleUser && !$user->name) {
        $user->update(['name' => ...]);
    }

    Auth::login($user);

    return redirect()->intended('/dashboard');
}

Verify id_token

Apple publishes public keys at https://appleid.apple.com/auth/keys. Verify with 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));

// Check: iss = appleid.apple.com, aud = client_id, exp, nonce

Relay Email and Limitations

If user hides email, Apple issues relay address @privaterelay.appleid.com. Emails only reach it if domain registered in Apple Developer Console → MoreConfigure Sign in with Apple for Email Communication.

Laravel Socialite

composer require laravel/socialite socialiteproviders/apple
// config/services.php
'apple' => [
    'client_id'     => env('APPLE_CLIENT_ID'),
    'client_secret' => env('APPLE_CLIENT_SECRET'), // generated JWT
    'redirect'      => env('APPLE_REDIRECT_URI'),
],

Socialite Apple provider handles most details, but client_secret needs periodic refresh.

Work Timeline

Stage Time
Apple Developer registration 0.5 day
client_secret generator + cron 1 day
OAuth callback + id_token verification 1.5 days
Relay email handling, name processing 0.5 day
Tests + real device verification 1 day

Total: 4–5 days.