serverNotificationHandler method

Future<Result> serverNotificationHandler(
  1. Session session,
  2. Request req
)

Handler for revoking sessions based on server-to-server notifications coming from Apple.

To be mounted as a POST handler under the URL configured in Apple's developer portal, for example:

  Router<Handler>()..post(
    '/hooks/apple-notification',
    handleAppleNotification, // your function to handle the notification
  );

If the notification is of type AppleServerNotificationConsentRevoked or AppleServerNotificationAccountDelete, all sessions based on the Apple authentication for that account will be revoked.

Implementation

Future<Result> serverNotificationHandler(
  final Session session,
  final Request req,
) async {
  final body = await utf8.decodeStream(req.body.read());
  final payload = (jsonDecode(body) as Map)['payload'] as String;

  final notification = await _signInWithApple.decodeAppleServerNotification(
    payload,
  );

  final userIdentifier = switch (notification) {
    AppleServerNotificationConsentRevoked() => notification.userIdentifier,
    AppleServerNotificationAccountDelete() => notification.userIdentifier,
    _ => null,
  };

  if (userIdentifier != null) {
    final appleAccount = await AppleAccount.db.findFirstRow(
      session,
      where: (final t) => t.userIdentifier.equals(userIdentifier),
    );

    if (appleAccount != null) {
      await _signInWithApple.revokeAuthorization(
        refreshToken: appleAccount.refreshToken,
        useBundleIdentifier:
            appleAccount.refreshTokenRequestedWithBundleIdentifier,
      );

      await _tokenManager.revokeAllTokens(
        session,
        authUserId: appleAccount.authUserId,
        method: AppleIdp.method,
      );

      if (notification is AppleServerNotificationAccountDelete) {
        await AppleAccount.db.deleteRow(session, appleAccount);
      }
    }
  }
  return Response.ok();
}