diff --git a/__tests__/index.test.js b/__tests__/index.test.js index 3b6b2a4..6c3c4b2 100644 --- a/__tests__/index.test.js +++ b/__tests__/index.test.js @@ -7,6 +7,7 @@ import appleSignin, { getAuthorizationToken, refreshAuthorizationToken, verifyIdToken, + verifyWebhookToken, _getApplePublicKeys, } from '../src/index'; @@ -17,6 +18,7 @@ describe('appleSignin test', () => { expect(appleSignin.getAuthorizationToken).toBeTruthy(); expect(appleSignin.refreshAuthorizationToken).toBeTruthy(); expect(appleSignin.verifyIdToken).toBeTruthy(); + expect(appleSignin.verifyWebhookToken).toBeTruthy(); expect(appleSignin._getApplePublicKeys).toBeTruthy(); }); @@ -26,6 +28,7 @@ describe('appleSignin test', () => { expect(getAuthorizationToken).toBeTruthy(); expect(refreshAuthorizationToken).toBeTruthy(); expect(verifyIdToken).toBeTruthy(); + expect(verifyWebhookToken).toBeTruthy(); expect(_getApplePublicKeys).toBeTruthy(); }); }); diff --git a/src/index.js b/src/index.js index e220e0c..35277fe 100644 --- a/src/index.js +++ b/src/index.js @@ -31,6 +31,53 @@ export type AppleIdTokenType = { email_verified: boolean, }; +export type AppleWebhookTokenEventType = { + /** The type of event. */ + type: + | 'email-disabled' + | 'email-enabled' + | 'consent-revoked' + | 'account-delete', + /** The unique identifier for the user. */ + sub: string, + /** The time the event occurred. */ + event_time: number, + /** The email address for the user. Provided on `email-disabled` and `email-enabled` events only. */ + email?: string, + /** A String or Boolean value that indicates whether the email shared by the user is the proxy address. The value of this claim is always true because the email events relate only to the user's private relay service forwarding preferences. Provided on `email-disabled` and `email-enabled` events only. */ + is_private_email?: 'true' | 'false' | boolean, +}; + +export type AppleWebhookTokenType = { + /** The issuer-registered claim key, which has the value https://appleid.apple.com. */ + iss: string, + /** Your client_id in your Apple Developer account. */ + aud: string, + /** The expiry time for the token. This value is typically set to five minutes. */ + exp: string, + /** The time the token was issued. */ + iat: string, + /** The unique identifier for this token. */ + jti: string, + /** The event description. */ + events: AppleWebhookTokenEventType, +}; + +type RawAppleWebhookTokenType = { + /** The issuer-registered claim key, which has the value https://appleid.apple.com. */ + iss: string, + /** Your client_id in your Apple Developer account. */ + aud: string, + /** The expiry time for the token. This value is typically set to five minutes. */ + exp: string, + /** The time the token was issued. */ + iat: string, + /** The unique identifier for this token. */ + jti: string, + /** The JSON-stringified event description. */ + events: string, +}; + export type AppleAuthorizationTokenResponseType = { /** A token used to access allowed data. */ access_token: string, @@ -285,6 +332,28 @@ const verifyIdToken = async ( ), ); +const verifyWebhookToken = async ( + /** payload provided by Apple server-to-server notification */ + webhookToken: string, + /** JWT verify options - Full list here https://github.com/auth0/node-jsonwebtoken#jwtverifytoken-secretorpublickey-options-callback */ + options: Object = {}, +): Promise => + new Promise((resolve, reject) => + jwt.verify( + webhookToken, + _getIdTokenApplePublicKey, + { + algorithms: 'RS256', + issuer: ENDPOINT_URL, + ...options, + }, + (error: Error, decoded: RawAppleWebhookTokenType) => + error + ? reject(error) + : resolve({ ...decoded, events: JSON.parse(decoded.events) }), + ), + ); + /** * Sets the fetch function * @@ -300,6 +369,7 @@ export { getAuthorizationToken, refreshAuthorizationToken, verifyIdToken, + verifyWebhookToken, // Internals - exposed for hacky people _getApplePublicKeys, _setFetch, @@ -312,6 +382,7 @@ export default { getAuthorizationToken, refreshAuthorizationToken, verifyIdToken, + verifyWebhookToken, // Internals - exposed for hacky people _getApplePublicKeys, _setFetch,