Apple Sign-in for Node.js

2.0.0 · active · verified Sun Apr 19

`apple-signin-auth` is a Node.js library designed to simplify server-side implementation of Apple's 'Sign in with Apple' authentication flow. It provides a comprehensive API for generating authorization URLs, securely creating and managing client secrets (JSON Web Tokens), and exchanging authorization codes obtained from Apple for user access and refresh tokens. The package is currently at version 2.0.0, which mandates Node.js 18 or newer due to its adoption of native `fetch`. The library demonstrates a moderately active release cadence, with recent updates focusing on modernizing its codebase and enhancing resilience. Its key strengths lie in abstracting the complexities of direct interaction with Apple's REST API, handling JWT client secret generation, supporting `code_verifier` for enhanced security, and providing a clear, developer-friendly interface for the complete Apple Sign-in process on backend applications.

Common errors

Warnings

Install

Imports

Quickstart

This quickstart demonstrates the full server-side Apple Sign-in flow: generating an authorization URL, creating a JWT client secret, and exchanging an authorization code for user tokens, including an example of handling the redirect callback.

import { getAuthorizationUrl, getClientSecret, getAuthorizationToken } from 'apple-signin-auth';
import type { AuthorizationTokenResponse } from 'apple-signin-auth';

// --- Configuration (replace with your actual values) ---
const CLIENT_ID = process.env.APPLE_CLIENT_ID ?? 'com.example.app';
const TEAM_ID = process.env.APPLE_TEAM_ID ?? 'YOUR_APPLE_TEAM_ID';
const KEY_IDENTIFIER = process.env.APPLE_KEY_IDENTIFIER ?? 'YOUR_KEY_IDENTIFIER';
const PRIVATE_KEY_STRING = process.env.APPLE_PRIVATE_KEY_STRING ?? '-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----'; // Make sure this is secure in production
const REDIRECT_URI = process.env.APPLE_REDIRECT_URI ?? 'http://localhost:3000/auth/apple/callback';

async function handleAppleSignIn(authorizationCode: string, state?: string) {
  // 1. Generate the client secret required for token exchange
  const clientSecret = getClientSecret({
    clientID: CLIENT_ID,
    teamID: TEAM_ID,
    privateKey: PRIVATE_KEY_STRING,
    keyIdentifier: KEY_IDENTIFIER,
    expAfter: 15777000, // Optional: JWT expiration time (default is 5 minutes)
  });

  // 2. Exchange the authorization code for access and refresh tokens
  try {
    const tokenResponse: AuthorizationTokenResponse = await getAuthorizationToken(authorizationCode, {
      clientID: CLIENT_ID,
      redirectUri: REDIRECT_URI,
      clientSecret: clientSecret,
      // code_verifier: 'your_code_verifier_if_used' // Optional, for PKCE flow
    });

    console.log('Successfully exchanged code for tokens:', tokenResponse);
    const { access_token, refresh_token, id_token, expires_in } = tokenResponse;

    // You would typically decode and verify the ID token here
    // and then save user session, profile data, tokens in your database.
    // Example: const decodedIdToken = await appleSignin.verifyIdToken(id_token, { audience: CLIENT_ID });
    // console.log('Decoded ID Token:', decodedIdToken);

    return tokenResponse;
  } catch (err) {
    console.error('Error during Apple Sign-in token exchange:', err);
    throw err;
  }
}

// Example usage for generating authorization URL (typically done on frontend or for redirect)
function getSignInUrl() {
  const options = {
    clientID: CLIENT_ID,
    redirectUri: REDIRECT_URI,
    state: 'random_csrf_token_here', // IMPORTANT: Generate a secure random string
    responseMode: 'form_post', // Or 'query', 'fragment'
    scope: 'email name', // Request email and name
  };
  const authorizationUrl = getAuthorizationUrl(options);
  console.log('Apple Sign-in Authorization URL:', authorizationUrl);
  return authorizationUrl;
}

// Simulate an incoming authorization code after user redirects
const simulateAuthorizationCode = async () => {
  console.log('\n--- Initiating simulated Apple Sign-in flow ---');
  getSignInUrl(); // This URL would be visited by the user in a browser

  // In a real application, 'some_authorization_code' and 'some_state' would come from the redirect callback
  const mockCode = 'MOCK_APPLE_AUTHORIZATION_CODE'; 
  const mockState = 'random_csrf_token_here';

  try {
    const result = await handleAppleSignIn(mockCode, mockState);
    console.log('\nSimulated Sign-in successful:', result);
  } catch (error) {
    console.error('\nSimulated Sign-in failed:', error);
  }
};

simulateAuthorizationCode();

view raw JSON →