Zum Hauptinhalt springen

Wie man sich mit Apple bei Capacitor (2026) anmeldet

Ein Capacitor-App auf iOS, Android und Web hinzufügen: Apple-Entwickler-Einstellungen, Plugin code, Backend-Token-Überprüfungen und häufige Fehler.

Artikelcredits

Martin Donadieu

Autor

Valeria

Rezensent

Jordan

Redakteur

Wie man sich mit Apple bei Capacitor (2026) anmeldet

Um eine Capacitor-App mit Sign in with Apple zu versehen, installieren Sie @capgo/capacitor-social-loginEnable the Sign in with Apple capability on your App ID und in Xcode aufrufen SocialLogin.initialize({ apple: {} })Dann aufrufen SocialLogin.login({ provider: 'apple' }). Bei iOS öffnet dies das native Apple Blatt und gibt einen Identitäts-Token zurück. Android und Web verwenden Apple’s Web OAuth-Flow, der eine Services-ID und einen HTTPS-Redirect-URL benötigt.

Diese Anleitung behandelt die Apple-Entwickler-Einrichtung, den Client code für iOS, Android und Web, die Verifizierung des Tokens auf Ihrem Backend und die Fehler, die Sie am häufigsten treffen werden. Sie richtet sich an Capacitor 8 und Xcode 26, die App Store Connect seit April 2026 für Uploads vorausgesetzt hat.

Was Sie vorher benötigen

Anforderung Warum
Bezahlte Mitgliedschaft im Apple-Entwickler-Programm App-IDs, Services-IDs und Sign in with Apple-Schlüssel sind nur für Mitglieder verfügbar
Ein Mac mit Xcode 26 Notwendig, um iOS-Apps in 2026 zu erstellen und hochzuladen
Capacitor 8-Projekt Plugin v8 zielt auf Capacitor 8 ab
Ein HTTPS-Domain, die Sie kontrollieren Nur für Android und Web. Apple lehnt ab localhost und einfache HTTP-Rückruf-URLs
Ein Backend-Endpunkt Immer zum Verifizieren von Token. Auf Android erhält es auch Apples Callback

Wenn Sie noch keine Signierzertifikate besitzen, erstellt der iOS-Zertifikatsgenerator erstellt sie ohne eine Mac-Schlüsselkette.

Wie Sign in with Apple auf jeder Plattform funktioniert

Apple liefert nur eine native SDK für seine eigenen Plattformen, daher unterscheidet sich der Ablauf:

Plattform Methode Kunden-ID, die verwendet wird Backend erforderlich für die Anmeldung
iOS Native ASAuthorizationAppleIDProvider sheet Ihr App-Bundle-Id No
Nein Apple OAuth in einem Chrome Custom Tab, Apple sendet Daten an Ihren Server, der leitet die Benutzer dann zurück in die App. Dienst-ID Services-ID
Ja Apple JS Popup Dienst-ID Nein (aber überprüfen Sie den Token)

Die Zielgruppe (aud) des Identitäts-Tokens folgt dem Client-ID. Token von iOS tragen Ihren Bundle-ID, Token von Android und Web tragen die Services ID. Ihr Backend muss beide akzeptieren.

Schritt 1: Konfigurieren Sie das Apple-Entwicklerkonto

Konfigurieren Sie die Fähigkeit auf Ihrem App-ID

  1. Öffnen Zertifikate, Identifikatoren und Profile und wählen Sie Identifikatoren.
  2. Öffnen Sie das App-ID, das Ihrem Capacitor entspricht appId (zum Beispiel) com.example.app. Erstelle es, wenn es nicht existiert.
  3. Unter Fähigkeiten, bestätige Anmeldung mit Apple und speichere. Lasse es als Haupt-App-ID, es sei denn, du gruppiert mehrere Apps.

Wenn Sie die Fähigkeiten eines bestehenden App-IDs ändern, müssen Sie die entsprechenden Provisionierungsprofile neu generieren. Die alten Profile enthalten die neuen Berechtigungen nicht.

Erstelle eine Services-ID (nur für Android und Web)

  1. In Identifikatoren, klicke + und wähle Dienstleistungs-IDs.
  2. Verwenden Sie eine Beschreibung wie „Beispiel Web-Login“ und einen Identifier wie com.example.app.signinDieser Wert wird zum clientId auf Android und Web.
  3. Öffnen Sie das neue Services-ID, setzen Sie das Häkchen Anmeldung mit Apple, und klicken Sie Konfigurieren.
  4. Wählen Sie Ihre App-ID als Haupt-App-ID.
  5. Hinzufügen Sie Ihren Domain unter Domains und Subdomains (kein Scheme, zum Beispiel auth.example.com).
  6. Fügen Sie die Rückruf-URLs unter Rückruf-URLs mit dem vollständigen https:// Weg, zum Beispiel https://auth.example.com/apple/callback. Für Web-Anmeldungen fügen Sie die Seite-URL hinzu, die die Anmeldung aufruft, mit und ohne Schlusspunkt.

Erstellen Sie einen Sign in with Apple-Schlüssel (Android und Server-Token-Übertragung)

  1. Gehe zu Schlüssel, klicke +, markiere Anmelden mit Apple, und klicke Einstellen um die primäre App-ID auszuwählen.
  2. Registrieren Sie die Schlüssel und laden Sie das .p8 Datei herunter. Apple lässt Sie es nur einmal herunterladen.
  3. Hinweis auf die Schlüssel-ID und Ihre Team-ID (gezeigt im oberen rechten Bereich des Entwicklerportals und unter Mitgliedschaft).

Ihr Server verwendet die Schlüssel, um das client_secret JWT zu signieren, das er an Apples Token-Endpunkt sendet.

Registrieren Sie E-Mail-Quellen, wenn Sie E-Mail senden

Benutzer können wählen Meine E-Mail verbergen, die Ihnen ermöglicht, sich anzumelden. @privaterelay.appleid.com . Wenn Sie dies überspringen, verschwinden Ihre Passwort-Restitutions- und Rechnungs-E-Mails stillschweigend. Dienste > Apple-Anmeldung für E-Mail-KommunikationDeaktivieren Sie diese Option und Ihre Passwörterrset- und Rechnungsemails verschwinden still und leise.

so ab, dass ihre SDKs nicht geliefert werden:

bun add @capgo/capacitor-social-login
bunx cap sync

Die Plugin verpackt mehrere Anbieter. Wenn Sie nur Apple (und vielleicht Google) verwenden, schalten Sie die anderen aus in capacitor.config.ts So ihre SDKs werden nicht geliefert:

import type { CapacitorConfig } from '@capacitor/cli';

const config: CapacitorConfig = {
  appId: 'com.example.app',
  appName: 'Example',
  webDir: 'dist',
  plugins: {
    SocialLogin: {
      providers: {
        apple: true,
        google: false,
        facebook: false,
        twitter: false,
      },
    },
  },
};

export default config;

Run bunx cap sync Ändern Sie diesen Block nicht erneut. Ein deaktivierter Anbieter ist bei der Ausführung nicht verfügbar, daher sollten Sie einen nicht deaktivieren, den Sie verwenden. AD_ID Warnungen über die Berechtigungen, die SDK in Google Play Console auslöst.

Schritt 3: iOS-Einrichtung

  1. Lauf bunx cap open ios.
  2. Wählen Sie App Schritt 3: iOS-Einrichtung Anmeldung & Funktionen, click Xcode schreibt, und fügen Sie Anmelden mit Apple.
  3. Stellen Sie sicher, dass der Bundle-Identifier dem von Ihnen konfigurierten App-ID entspricht.

Xcode schreibt com.apple.developer.applesignin auf App.entitlements. Wenn Sie in CI oder mit Capgo Buildcommitte das Entitlements-Datei, andernfalls produziert die Cloud-Build eine App, die mit einem Fehler fehlschlägt ASAuthorizationError code 1000.

No Info.plist URL-Schema oder AppDelegate Eine Änderung ist erforderlich für Apple auf iOS.

Schritt 4: Android-Einrichtung

Apple has no Android SDK. The plugin opens Apple’s authorize page in a Custom Tab with your Services ID. Apple then sends the result as a form POST to your HTTPS return URL. Your server exchanges the code, then redirects to a deep link that reopens the app with the tokens.

In android/app/src/main/AndroidManifest.xml, innerhalb des MainActivity <activity> element:

<intent-filter>
    <action android:name="android.intent.action.VIEW" />
    <category android:name="android.intent.category.DEFAULT" />
    <category android:name="android.intent.category.BROWSABLE" />
    <data android:scheme="com.example.app" android:host="apple-login" />
</intent-filter>

Richten Sie die Absicht an das Plugin weiter

Bearbeiten MainActivity.java so dass der tiefere Link das Plugin erreicht:

package com.example.app;

import android.content.Intent;
import android.net.Uri;
import com.getcapacitor.BridgeActivity;
import com.getcapacitor.Plugin;
import com.getcapacitor.PluginHandle;
import ee.forgr.capacitor.social.login.SocialLoginPlugin;

public class MainActivity extends BridgeActivity {

    @Override
    protected void onNewIntent(Intent intent) {
        Uri data = intent.getData();
        if (Intent.ACTION_VIEW.equals(intent.getAction()) && data != null
                && "apple-login".equals(data.getHost())) {
            PluginHandle handle = getBridge().getPlugin("SocialLogin");
            if (handle != null) {
                Plugin plugin = handle.getInstance();
                if (plugin instanceof SocialLoginPlugin) {
                    ((SocialLoginPlugin) plugin).handleAppleLoginIntent(intent);
                    return;
                }
            }
        }
        super.onNewIntent(intent);
    }
}

Filtern Sie auf dem Host, um sicherzustellen, dass Ihre anderen tiefen Links (Passwort-Restart, Marketing-Links) weiterhin funktionieren.

Der Callback-Endpunkt

Apple sendet code, id_token, state, und bei der ersten Anmeldung einen user eine JSON-Zeichenfolge an Ihre Rückruf-URL. Der Endpunkt muss die code austauschen und zu der App umleiten, die success=true zusammen mit den Token, die der Plugin-Vertrag parsen muss. Ein minimaler Hono-Beispiel, der jose:

import { Hono } from 'hono';
import { SignJWT, importPKCS8, createRemoteJWKSet, jwtVerify } from 'jose';
import { saveAppleRefreshToken } from './db'; // your own persistence layer

const app = new Hono();

const TEAM_ID = process.env.APPLE_TEAM_ID!;
const KEY_ID = process.env.APPLE_KEY_ID!;
const SERVICE_ID = process.env.APPLE_SERVICE_ID!; // com.example.app.signin
const PRIVATE_KEY = process.env.APPLE_PRIVATE_KEY!; // contents of the .p8 file
const APP_REDIRECT = 'com.example.app://apple-login';
const APPLE_JWKS = createRemoteJWKSet(new URL('https://appleid.apple.com/auth/keys'));

async function appleClientSecret() {
  const key = await importPKCS8(PRIVATE_KEY, 'ES256');
  return new SignJWT({})
    .setProtectedHeader({ alg: 'ES256', kid: KEY_ID })
    .setIssuer(TEAM_ID)
    .setSubject(SERVICE_ID)
    .setAudience('https://appleid.apple.com')
    .setIssuedAt()
    .setExpirationTime('5m')
    .sign(key);
}

app.post('/apple/callback', async (c) => {
  const form = await c.req.parseBody();
  const code = String(form.code ?? '');
  if (!code) {
    return c.redirect(`${APP_REDIRECT}?success=false`);
  }

  // `form.user` is only present on the first authorization. Store it now.

  const res = await fetch('https://appleid.apple.com/auth/token', {
    method: 'POST',
    headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
    body: new URLSearchParams({
      client_id: SERVICE_ID,
      client_secret: await appleClientSecret(),
      code,
      grant_type: 'authorization_code',
      redirect_uri: 'https://auth.example.com/apple/callback',
    }),
  });
  if (!res.ok) {
    return c.redirect(`${APP_REDIRECT}?success=false`);
  }
  const tokens = await res.json();

  // Verify the identity token, then keep the long-lived refresh token on the server.
  // Only the short-lived tokens go back to the app in the deep link.
  const { payload } = await jwtVerify(tokens.id_token, APPLE_JWKS, {
    issuer: 'https://appleid.apple.com',
    audience: SERVICE_ID,
  });
  if (tokens.refresh_token) {
    await saveAppleRefreshToken(String(payload.sub), tokens.refresh_token);
  }
  const params = new URLSearchParams({
    success: 'true',
    access_token: tokens.access_token,
    id_token: tokens.id_token,
  });
  return c.redirect(`${APP_REDIRECT}?${params}`);
});

export default app;

Das Plugin liest die Token aus der tiefen-Link-Abfragezeichenfolge, sodass alles, was Sie dort einfügen, in Protokollen landen kann oder von einem anderen App, das den gleichen benutzerdefinierten Scheme registriert, gelesen werden kann. Senden Sie nur die kurzlebigen access_token und id_token, nie das Refresh-Token, überprüfen Sie die id_token Signatur und nonce auf Ihrem Server, bevor Sie sie vertrauen, und verwenden Sie einen einzigartigen Scheme für Ihre App (Ihre umgekehrte Bundle-ID).

Der client_secret JWT kann bis zu sechs Monate lang gültig sein, aber die Erzeugung eines kurzen pro Anfrage vermeidet einen Ablaufdatum-Ausfall. Halten Sie die .p8 Datei in Ihrem geheimen Manager, nie in der App-Bundle.

Schritt 5: Web-Einrichtung

Die Web-Build verwendet Apple JS mit der Services-ID. Fügen Sie die genaue Seite-URL hinzu, die den Login auslöst, zu den Rückgabewerten der Services-ID. Apple akzeptiert localhost, also testen Sie den Web-Login auf einem bereitgestellten Vorabdomänen- oder durch einen Tunnel mit einem realen Hostnamen.

Schritt 6: Initialisierung und Anmeldung

Initialisiere einmalig bei App-Start. Übergebe die redirectUrl nur auf Android und Web. Auf iOS wird ein nicht leerer redirectUrl macht das Plugin den Ergebnis an die URL POSTen, was du bei der nativen Fluss nicht haben möchtest.

import { Capacitor } from '@capacitor/core';
import { SocialLogin } from '@capgo/capacitor-social-login';

const platform = Capacitor.getPlatform();

export async function initAuth() {
  await SocialLogin.initialize({
    apple: {
      clientId: platform === 'ios' ? 'com.example.app' : 'com.example.app.signin',
      redirectUrl:
        platform === 'android'
          ? 'https://auth.example.com/apple/callback'
          : platform === 'web'
            ? 'https://app.example.com/login'
            : '',
    },
  });
}

Dann löst die Anmeldung von einem Button aus. Verwende einen zufälligen Nonce, damit dein Server wiederholte Tokens ablehnen kann:

import { SocialLogin } from '@capgo/capacitor-social-login';

export async function signInWithApple() {
  const nonce = crypto.randomUUID();

  try {
    const { result } = await SocialLogin.login({
      provider: 'apple',
      options: {
        scopes: ['email', 'name'],
        nonce,
      },
    });

    if (!result.idToken) {
      throw new Error('Apple did not return an identity token');
    }

    // Send to your backend. Name and email are only present on the first login.
    const response = await fetch('https://api.example.com/auth/apple', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        idToken: result.idToken,
        nonce,
        givenName: result.profile.givenName,
        familyName: result.profile.familyName,
      }),
    });
    return response.json();
  } catch (error: any) {
    if (error?.code === 'USER_CANCELLED') {
      return null; // user closed the sheet, not a failure
    }
    throw error;
  }
}

Die Antwort gibt dir:

Feld Inhalt
result.idToken Signierter JWT von Apple, das Ding, das dein Server überprüft
result.profile.user Stabiles Benutzerkonto von Apple (gleich dem sub Behauptung)
result.profile.email E-Mail-Adresse oder privater Relay-Adresse, wenn gewährt
result.profile.givenName / familyName Nur bei der ersten Autorisierung
result.accessToken Mit den Standardeinstellungen hält diese die Autorisierung code, kein echter Zugriffstoken
result.authorizationCode Präsentiert, wenn Sie mit} useProperTokenExchange: true

Wenn Ihr Server Apple-Refresh-Tokens benötigt (z.B. um den Revoke-Endpunkt aufzurufen, wenn ein Benutzer sein Konto löscht), setzen Sie useProperTokenExchange: true im apple Konfiguration und austauschen Sie authorizationCode auf dem Server.

Schritt 7: Überprüfen Sie die Identitäts-Token auf Ihrem Backend

Kontext: Über Capgo-Seite. Rolle: Benutzerschnittstelle-Label. Gesehen in: Seite über about.astro. Nachrichtenschlüssel `about_how_step_label` (Über How Schritt Label).

import { createRemoteJWKSet, jwtVerify } from 'jose';

const appleKeys = createRemoteJWKSet(new URL('https://appleid.apple.com/auth/keys'));

export async function verifyAppleToken(idToken: string, expectedNonce: string) {
  const { payload } = await jwtVerify(idToken, appleKeys, {
    issuer: 'https://appleid.apple.com',
    audience: ['com.example.app', 'com.example.app.signin'], // bundle ID + Services ID
  });

  if (payload.nonce !== expectedNonce) {
    throw new Error('Nonce mismatch');
  }

  return {
    appleUserId: payload.sub as string,
    email: payload.email as string | undefined,
    emailVerified: payload.email_verified === true || payload.email_verified === 'true',
  };
}

Key the user record on sub, not on email. The email can be a relay address, and users can stop sharing it. After verification, issue your own session token. If you use Supabase or Firebase, they verify the token for you, see Supabase mit Capacitor Social Login.

Supabase mit __CAPGO_KEEP_0__ Social Login

  • Richtlinie 4.8: Wenn Sie Google, Facebook oder einen anderen Drittanbieter-Login als Hauptsystem für Benutzerkonten anbieten, müssen Sie auch eine gleichwertige, datenschutzorientierte Option anbieten. Sign in with Apple qualifiziert sich dafür.
  • Richtlinie 5.1.1(v): Apps, die Benutzern ermöglichen, Konten zu erstellen, müssen ihnen ermöglichen, das Konto im App zu löschen. Für Benutzer von Sign in with Apple rufen Sie Apple’s https://appleid.apple.com/auth/revoke Endpunkt bei der Löschung auf. Siehe unsere Anleitung zur Konto-Löschung.
  • Knopfdesign: Verwenden Sie die von Apple genehmigten Knopfstile und machen Sie den Knopf mindestens so prominent wie andere Login-Knöpfe.

Problembehandlung

Symptom Wahrscheinliche Ursache Lösung
ASAuthorizationError code 1000 auf iOS Fähigkeit oder Berechtigung fehlt im Zielobjekt Fügen Sie Sign in with Apple in Xcode hinzu, committen Sie App.entitlements, regenerieren Sie Profile
Code 1001 auf iOS Benutzer stornierte Der Plugin lehnt mit USER_CANCELLED, behandeln Sie es als Nichtfehler
invalid_client auf Android oder Web Falsch clientId (Bundle-ID wird anstelle von Services-ID verwendet oder schlecht) client_secret Verwenden Sie die Services-ID, überprüfen Sie Team-ID, Key-ID und Schlüsselinhalt
invalid_request: Invalid redirect_uri Rückruf-URL ist nicht genau registriert Fügen Sie die vollständige https:// URL zur Services-ID hinzu, passen Sie die Schlusspunkte an
Die App kehrt nicht zurück nach Android-Anmeldung Die Intent-Filter-Scheme oder -Host unterscheidet sich von der Server-Redirect-URL Vergleichen com.example.app://apple-login Zeichen für Zeichen
apple.android.redirectUrl is null or empty Nein redirectUrl auf Android Geben Sie Ihre HTTPS-Rückruf-URL mit der Initialisierung auf Android an
Name und E-Mail sind null Nicht die erste Autorisierung Lese sie aus Ihrer Datenbank. Entziehe der App die Berechtigung in den Geräte-Einstellungen, um erneut zu testen.
Token wurde vom Backend abgelehnt: aud mismatch Der Server akzeptiert nur eine Zielgruppe Accept both bundle ID and Services ID

Lieferung von Korrekturen nach der Veröffentlichung

Die meisten Auth-Bugs leben in TypeScript: eine falsche Client-ID pro Plattform, ein fehlender Nonce, schlechte Fehlerbehandlung. Diese können den Benutzern am gleichen Tag mit Capgo Live-Updates ohne Warten auf die App-Überprüfung. Änderungen an den Berechtigungen, dem Android-Manifest oder MainActivity sind native und erfordern eine neue App-Veröffentlichung.

Wo geht es als Nächstes?

Live Updates für Capacitor-Apps

Wenn ein Bug im Weblayer live ist, schicken Sie die Reparatur über Capgo anstatt Tage auf die Genehmigung durch den App Store zu warten. Die Benutzer erhalten die Aktualisierung im Hintergrund, während native Änderungen im normalen Review-Prozess bleiben.

Neuestes aus unserem Blog

Capgo gibt Ihnen die besten Einblicke, die Sie benötigen, um ein wirklich professionelles Mobiltelefon-App zu erstellen.