### Install apple-auth Package Source: https://github.com/ananay/apple-auth/blob/master/README.md Install the library using npm. Ensure you have Node.js and npm installed. ```bash npm install apple-auth ``` -------------------------------- ### Complete Express.js Integration with Apple Auth Source: https://context7.com/ananay/apple-auth/llms.txt Full Express.js example demonstrating the Apple Sign-In flow. It includes setup for session management, loading configuration, initiating the login URL, and handling the callback to exchange codes for tokens. User data is stored in the session upon successful authentication. ```javascript // Complete Express.js integration example const express = require('express'); const fs = require('fs'); const AppleAuth = require('apple-auth'); const jwt = require('jsonwebtoken'); const session = require('express-session'); const app = express(); app.use(express.urlencoded({ extended: true })); app.use(session({ secret: 'session-secret', resave: false, saveUninitialized: true })); // Load configuration from file const config = JSON.parse(fs.readFileSync('./config/config.json')); const auth = new AppleAuth(config, './config/AuthKey.p8', 'file', { debug: true }); // Initiate Sign in with Apple app.get('/auth/apple', (req, res) => { const url = auth.loginURL(); req.session.appleState = auth.state; res.redirect(url); }); // Handle Apple's callback app.post('/auth/apple/callback', async (req, res) => { try { if (req.body.state !== req.session.appleState) { throw new Error('State verification failed'); } const response = await auth.accessToken(req.body.code); const decoded = jwt.decode(response.id_token); // First-time login includes user data const userData = req.body.user ? JSON.parse(req.body.user) : null; req.session.user = { id: decoded.sub, email: decoded.email, name: userData?.name, tokens: response }; res.redirect('/dashboard'); } catch (error) { res.status(500).send('Authentication failed: ' + error.message); } }); app.listen(3000); ``` -------------------------------- ### GET /auth/apple Source: https://context7.com/ananay/apple-auth/llms.txt Generates the Apple login URL and stores the state for CSRF protection. ```APIDOC ## GET /auth/apple ### Description Generates the Apple login URL and stores the state for CSRF protection. The state is generated when loginURL() is called and should be stored in the session, then verified when Apple redirects back to your callback URL. ### Method GET ### Endpoint /auth/apple ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```json { "example": "No request body needed for this endpoint." } ``` ### Response #### Success Response (302) - Redirects the user to the Apple login page. #### Response Example ```json { "example": "Redirects to Apple's authorization server." } ``` ``` -------------------------------- ### Initialize AppleAuth Library Source: https://github.com/ananay/apple-auth/blob/master/README.md Initialize the AppleAuth library with configuration details. The configuration can be read from a file, and the private key path must be provided. ```javascript const fs = require('fs'); const AppleAuth = require('apple-auth'); const config = fs.readFileSync("./config/config"); const auth = new AppleAuth(config, './config/AuthKey.p8'); ``` -------------------------------- ### Initialize AppleAuth Constructor Source: https://context7.com/ananay/apple-auth/llms.txt Configure and initialize the AppleAuth client. Supports private keys via file path or text content, and includes an option for debug mode. Ensure client ID, team ID, redirect URI, and key ID are correctly set. ```javascript const fs = require('fs'); const AppleAuth = require('apple-auth'); // Configuration object const config = { client_id: 'com.example.myapp', // Services ID from Apple Developer Portal team_id: 'ABCDE12345', // 10-character Team ID redirect_uri: 'https://example.com/callback', key_id: 'FGHIJ67890', // Private Key ID scope: 'name email' // Requested user information }; // Initialize with private key file path const auth = new AppleAuth(config, './config/AuthKey.p8'); // Or initialize with private key as text const privateKeyContent = fs.readFileSync('./config/AuthKey.p8', 'utf8'); const authWithText = new AppleAuth(config, privateKeyContent, 'text'); // Initialize with debug mode enabled const authDebug = new AppleAuth(config, './config/AuthKey.p8', 'file', { debug: true }); // Using config from JSON file const configFromFile = JSON.parse(fs.readFileSync('./config/config.json')); const authFromFile = new AppleAuth(configFromFile, './config/AuthKey.p8'); ``` -------------------------------- ### AppleAuth Constructor Source: https://context7.com/ananay/apple-auth/llms.txt Initializes the Apple Auth client with configuration options. Supports private key as a file path or text content, with an optional debug mode. ```APIDOC ## AppleAuth Constructor ### Description Initializes the Apple Auth client with configuration options including client ID (Services ID), team ID, redirect URI, key ID, and scope. The private key can be provided as a file path or as raw text content, with an optional debug mode for verbose error logging. ### Method `new AppleAuth(config, privateKey, [keyFormat], [options])` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```javascript const fs = require('fs'); const AppleAuth = require('apple-auth'); // Configuration object const config = { client_id: 'com.example.myapp', // Services ID from Apple Developer Portal team_id: 'ABCDE12345', // 10-character Team ID redirect_uri: 'https://example.com/callback', key_id: 'FGHIJ67890', // Private Key ID scope: 'name email' // Requested user information }; // Initialize with private key file path const auth = new AppleAuth(config, './config/AuthKey.p8'); // Or initialize with private key as text const privateKeyContent = fs.readFileSync('./config/AuthKey.p8', 'utf8'); const authWithText = new AppleAuth(config, privateKeyContent, 'text'); // Initialize with debug mode enabled const authDebug = new AppleAuth(config, './config/AuthKey.p8', 'file', { debug: true }); // Using config from JSON file const configFromFile = JSON.parse(fs.readFileSync('./config/config.json')); const authFromFile = new AppleAuth(configFromFile, './config/AuthKey.p8'); ``` ### Response #### Success Response (200) None (Constructor does not return a value, it initializes an object) #### Response Example None ``` -------------------------------- ### POST /callback Source: https://context7.com/ananay/apple-auth/llms.txt Handles the callback from Apple after user authentication, verifies the state, and exchanges the authorization code for tokens. ```APIDOC ## POST /callback ### Description Handles the callback from Apple after user authentication. It verifies the state parameter to prevent CSRF attacks and then exchanges the authorization code for access and refresh tokens. ### Method POST ### Endpoint /callback ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body - **code** (string) - Required - The authorization code received from Apple. - **state** (string) - Required - The state string generated during the login request, used for CSRF protection. ### Request Example ```json { "code": "AUTHORIZATION_CODE_FROM_APPLE", "state": "STATE_STRING_FROM_SESSION" } ``` ### Response #### Success Response (200) - **success** (boolean) - Indicates if the token exchange was successful. #### Response Example ```json { "success": true } ``` #### Error Response (403) - **error** (string) - Message indicating a state mismatch, suggesting a possible CSRF attack. ``` -------------------------------- ### Initialize AppleAuth with Debug Mode Source: https://github.com/ananay/apple-auth/blob/master/SETUP.md Enable debugging by passing an object with `debug: true` when initializing the library. This logs failed requests and provides more detailed error messages. ```javascript let auth = new AppleAuth( config, SECRET_KEY, TEXT_METHOD, { debug: true } ); ``` -------------------------------- ### Exchange Authorization Code for Access Token Source: https://context7.com/ananay/apple-auth/llms.txt Use this when a user signs in with Apple for the first time. It exchanges the authorization code received from Apple for tokens. Ensure the state parameter is verified to prevent CSRF attacks. The id_token contains user identity information, and the user name is only provided on the first login. ```javascript const AppleAuth = require('apple-auth'); const express = require('express'); const jwt = require('jsonwebtoken'); const app = express(); app.use(express.urlencoded({ extended: true })); const config = { client_id: 'com.example.myapp', team_id: 'ABCDE12345', redirect_uri: 'https://example.com/callback', key_id: 'FGHIJ67890', scope: 'name email' }; const auth = new AppleAuth(config, './config/AuthKey.p8'); // Apple sends POST request to callback with authorization code app.post('/callback', async (req, res) => { const { code, state, user } = req.body; // Verify state to prevent CSRF attacks if (state !== req.session.appleAuthState) { return res.status(403).send('Invalid state parameter'); } try { // Exchange authorization code for tokens const tokenResponse = await auth.accessToken(code); // tokenResponse structure: // { // access_token: 'a1b2c3...', // token_type: 'bearer', // expires_in: 3600, // refresh_token: 'r4e5f6...', // id_token: 'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...' // } // Decode the id_token to get user information const idToken = jwt.decode(tokenResponse.id_token); // idToken contains: { sub: 'unique_user_id', email: 'user@example.com', ... } // IMPORTANT: User name is only provided on FIRST login // Store it immediately if present let userName = null; if (user) { const userData = JSON.parse(user); userName = userData.name; // { firstName: 'John', lastName: 'Doe' } } // Store user in database const userData = { appleId: idToken.sub, email: idToken.email, name: userName, refreshToken: tokenResponse.refresh_token }; res.json({ success: true, user: userData }); } catch (error) { console.error('Apple Auth Error:', error); res.status(500).json({ error: 'Authentication failed' }); } }); ``` -------------------------------- ### Apple Auth Configuration JSON Source: https://context7.com/ananay/apple-auth/llms.txt Defines Apple Developer credentials including client ID, team ID, redirect URI, key ID, and requested scopes. Ensure client_id matches your Services ID for web applications. ```json { "client_id": "com.example.myapp.service", "team_id": "ABCDE12345", "redirect_uri": "https://example.com/auth/apple/callback", "key_id": "FGHIJ67890", "scope": "name email" } ``` -------------------------------- ### Configuration JSON for AppleAuth Source: https://github.com/ananay/apple-auth/blob/master/SETUP.md This JSON structure is used to configure the AppleAuth library. Ensure all fields are correctly populated with your Apple Developer account details. ```json { "client_id": "", "team_id": "", "redirect_uri": "", "key_id": "", "scope": "" } ``` -------------------------------- ### loginURL() Source: https://context7.com/ananay/apple-auth/llms.txt Generates the Apple OAuth 2.0 authorization URL for redirecting users to Apple's sign-in page. Includes state parameter for CSRF protection and specifies response types and mode. ```APIDOC ## loginURL() ### Description Generates the Apple OAuth 2.0 authorization URL that redirects users to Apple's sign-in page. The method automatically generates a random state parameter for CSRF protection and configures the request for form_post response mode with both code and id_token response types. ### Method `auth.loginURL()` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```javascript const AppleAuth = require('apple-auth'); const express = require('express'); const app = express(); const config = { client_id: 'com.example.myapp', team_id: 'ABCDE12345', redirect_uri: 'https://example.com/callback', key_id: 'FGHIJ67890', scope: 'name email' }; const auth = new AppleAuth(config, './config/AuthKey.p8'); // Route to initiate Apple Sign In app.get('/auth/apple', (req, res) => { const loginUrl = auth.loginURL(); // Store state for verification in callback req.session.appleAuthState = auth.state; // Redirect user to Apple's authorization page res.redirect(loginUrl); }); ``` ### Response #### Success Response (200) - **loginUrl** (string) - The generated Apple OAuth 2.0 authorization URL. #### Response Example ``` https://appleid.apple.com/auth/authorize?response_type=code%20id_token&client_id=com.example.myapp&redirect_uri=https%3A%2F%2Fexample.com%2Fcallback&state=a1b2c3d4e5&scope=name%20email&response_mode=form_post ``` ``` -------------------------------- ### DELETE /account Source: https://context7.com/ananay/apple-auth/llms.txt Handles complete account deletion, including revoking the Apple token if connected. ```APIDOC ## DELETE /account ### Description Handles complete account deletion as per Apple App Store requirements. This endpoint first attempts to revoke the user's Apple token if one is associated with the account, and then proceeds to delete the user's account. ### Method DELETE ### Endpoint /account ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```json { "example": "No request body needed for this endpoint." } ``` ### Response #### Success Response (200) - **success** (boolean) - Indicates if the account deletion was successful. - **message** (string) - A message confirming the account deletion. #### Response Example ```json { "success": true, "message": "Account deleted" } ``` ``` -------------------------------- ### Generate Apple Sign In URL Source: https://context7.com/ananay/apple-auth/llms.txt Create the Apple OAuth 2.0 authorization URL using the loginURL() method. This URL is used to redirect users to Apple's sign-in page. The state parameter is automatically generated for CSRF protection. ```javascript const AppleAuth = require('apple-auth'); const express = require('express'); const app = express(); const config = { client_id: 'com.example.myapp', team_id: 'ABCDE12345', redirect_uri: 'https://example.com/callback', key_id: 'FGHIJ67890', scope: 'name email' }; const auth = new AppleAuth(config, './config/AuthKey.p8'); // Route to initiate Apple Sign In app.get('/auth/apple', (req, res) => { const loginUrl = auth.loginURL(); // Store state for verification in callback req.session.appleAuthState = auth.state; // Redirect user to Apple's authorization page res.redirect(loginUrl); }); // Generated URL format: // https://appleid.apple.com/auth/authorize?response_type=code%20id_token&client_id=com.example.myapp&redirect_uri=https%3A%2F%2Fexample.com%2Fcallback&state=a1b2c3d4e5&scope=name%20email&response_mode=form_post ``` -------------------------------- ### Refresh Access Token using Refresh Token Source: https://context7.com/ananay/apple-auth/llms.txt Use this middleware to refresh expired access tokens. It checks if the current access token is nearing expiration and uses the stored refresh token to obtain a new one. If the refresh fails, the user is redirected to re-authenticate. Ensure the user object has properties for `accessToken`, `tokenExpiry`, and `refreshToken`. ```javascript const AppleAuth = require('apple-auth'); const config = { client_id: 'com.example.myapp', team_id: 'ABCDE12345', redirect_uri: 'https://example.com/callback', key_id: 'FGHIJ67890', scope: 'name email' }; const auth = new AppleAuth(config, './config/AuthKey.p8'); // Middleware to refresh expired tokens async function refreshAppleToken(req, res, next) { const user = req.user; // Check if access token is expired or about to expire if (user.tokenExpiry < Date.now() + 300000) { // 5 minutes buffer try { // Use stored refresh token to get new access token const tokenResponse = await auth.refreshToken(user.refreshToken); // tokenResponse structure: // { // access_token: 'new_access_token...', // token_type: 'bearer', // expires_in: 3600, // refresh_token: 'new_or_same_refresh_token...', // id_token: 'new_id_token...' // } // Update stored tokens user.accessToken = tokenResponse.access_token; user.tokenExpiry = Date.now() + (tokenResponse.expires_in * 1000); // Update refresh token if a new one was provided if (tokenResponse.refresh_token) { user.refreshToken = tokenResponse.refresh_token; } await user.save(); } catch (error) { console.error('Token refresh failed:', error); // Redirect to re-authenticate if refresh fails return res.redirect('/auth/apple'); } } next(); } ``` -------------------------------- ### refreshToken - Obtain New Access Token Source: https://context7.com/ananay/apple-auth/llms.txt Obtains a new access token using a previously stored refresh token. This allows maintaining user sessions without requiring re-authentication. ```APIDOC ## refreshToken(refreshToken) ### Description Obtains a new access token using a previously stored refresh token. This allows maintaining user sessions without requiring re-authentication. Returns a promise with the same token response structure as accessToken(). ### Method POST (Implicitly via library function) ### Endpoint N/A (This is a client-side library function call) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None (Function parameter) - **refreshToken** (string) - Required - The refresh token obtained previously. ### Request Example ```javascript const tokenResponse = await auth.refreshToken(user.refreshToken); ``` ### Response #### Success Response - **access_token** (string) - The new access token. - **token_type** (string) - The type of token, typically 'bearer'. - **expires_in** (integer) - The time in seconds until the new access token expires. - **refresh_token** (string) - The new or same refresh token. - **id_token** (string) - A new JWT containing user identity information. #### Response Example ```json { "access_token": "new_access_token...", "token_type": "bearer", "expires_in": 3600, "refresh_token": "new_or_same_refresh_token...", "id_token": "new_id_token..." } ``` ``` -------------------------------- ### accessToken - Exchange Authorization Code for Access Token Source: https://context7.com/ananay/apple-auth/llms.txt Exchanges the authorization code received from Apple's callback for an access token. This endpoint is crucial for completing the OAuth 2.0 flow with Apple Sign In. ```APIDOC ## POST /callback ### Description Exchanges the authorization code received from Apple's callback for an access token. Returns a promise that resolves to an object containing the access_token, id_token, refresh_token, expires_in, and token_type. The id_token is a JWT that contains user identity information. ### Method POST ### Endpoint /callback ### Parameters #### Request Body - **code** (string) - Required - The authorization code received from Apple. - **state** (string) - Required - The state parameter used to prevent CSRF attacks. - **user** (string) - Optional - JSON string containing user's name, provided only on the first login. ### Request Example ```json { "code": "AUTHORIZATION_CODE", "state": "STATE_VALUE", "user": "{\"name\": {\"firstName\": \"John\", \"lastName\": \"Doe\"}}" } ``` ### Response #### Success Response (200) - **access_token** (string) - The access token for API requests. - **token_type** (string) - The type of token, typically 'bearer'. - **expires_in** (integer) - The time in seconds until the access token expires. - **refresh_token** (string) - The token used to obtain new access tokens. - **id_token** (string) - A JWT containing user identity information. #### Response Example ```json { "access_token": "a1b2c3...", "token_type": "bearer", "expires_in": 3600, "refresh_token": "r4e5f6...", "id_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..." } ``` ``` -------------------------------- ### Manage CSRF Protection State with Apple Auth Source: https://context7.com/ananay/apple-auth/llms.txt The state property returns the randomly generated state string used for CSRF protection during the OAuth flow. Store this in the session and verify it when Apple redirects back to your callback URL. ```javascript const AppleAuth = require('apple-auth'); const express = require('express'); const session = require('express-session'); const app = express(); app.use(session({ secret: 'your-secret-key', resave: false, saveUninitialized: true })); const config = { client_id: 'com.example.myapp', team_id: 'ABCDE12345', redirect_uri: 'https://example.com/callback', key_id: 'FGHIJ67890', scope: 'name email' }; const auth = new AppleAuth(config, './config/AuthKey.p8'); app.get('/auth/apple', (req, res) => { const loginUrl = auth.loginURL(); // State is a random hex string (e.g., 'a1b2c3d4e5') // Store it for verification in the callback req.session.appleState = auth.state; res.redirect(loginUrl); }); app.post('/callback', async (req, res) => { const { code, state } = req.body; // CRITICAL: Verify state to prevent CSRF attacks if (state !== req.session.appleState) { return res.status(403).json({ error: 'State mismatch - possible CSRF attack' }); } // Clear state from session delete req.session.appleState; // Continue with token exchange... const tokenResponse = await auth.accessToken(code); res.json({ success: true }); }); ``` -------------------------------- ### Revoke User Access Token with Apple Auth Source: https://context7.com/ananay/apple-auth/llms.txt Call this function when users disconnect their Apple account. The `unique_id` parameter is the access token to revoke. ```javascript const AppleAuth = require('apple-auth'); const express = require('express'); const app = express(); const config = { client_id: 'com.example.myapp', team_id: 'ABCDE12345', redirect_uri: 'https://example.com/callback', key_id: 'FGHIJ67890', scope: 'name email' }; const auth = new AppleAuth(config, './config/AuthKey.p8'); // Route to disconnect Apple account app.post('/auth/apple/revoke', async (req, res) => { const user = req.user; if (!user.appleAccessToken) { return res.status(400).json({ error: 'No Apple account connected' }); } try { // Revoke the access token await auth.revokeToken(user.appleAccessToken); // Clear Apple-related data from user record user.appleId = null; user.appleAccessToken = null; user.appleRefreshToken = null; await user.save(); res.json({ success: true, message: 'Apple account disconnected' }); } catch (error) { console.error('Token revocation failed:', error); res.status(500).json({ error: 'Failed to revoke token' }); } }); // Route for complete account deletion (Apple App Store requirement) app.delete('/account', async (req, res) => { const user = req.user; // Revoke Apple token before deleting account if (user.appleAccessToken) { try { await auth.revokeToken(user.appleAccessToken); } catch (error) { console.warn('Could not revoke Apple token:', error); } } // Delete user account await user.destroy(); res.json({ success: true, message: 'Account deleted' }); }); ``` -------------------------------- ### POST /auth/apple/revoke Source: https://context7.com/ananay/apple-auth/llms.txt Revokes a user's access token, effectively logging them out from Apple's perspective. This should be called when users want to disconnect their Apple account from your application. ```APIDOC ## POST /auth/apple/revoke ### Description Revokes a user's access token, effectively logging them out from Apple's perspective. This should be called when users want to disconnect their Apple account from your application. ### Method POST ### Endpoint /auth/apple/revoke ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```json { "example": "No request body needed for this endpoint." } ``` ### Response #### Success Response (200) - **success** (boolean) - Indicates if the token revocation was successful. - **message** (string) - A message confirming the Apple account disconnection. #### Response Example ```json { "success": true, "message": "Apple account disconnected" } ``` #### Error Response (400) - **error** (string) - Message indicating no Apple account is connected. #### Error Response (500) - **error** (string) - Message indicating failure to revoke token. ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.