IAC Membership Inbound API

Overview

The IAC Members API provides a secure HTTPS endpoint used by EAA’s system to push individual membership updates directly into our Drupal site.
Each POSTed record is validated, queued, and then synced to the corresponding Drupal user account.

  • Endpoint: https://www.iac.org/api/iac/members

  • Auth: Bearer token (shared secret)

  • Queue: iac_members_api_inbound (processed via cron)

  • Primary code: /web/modules/custom/iac_members_api


How It Works

  1. Inbound POST

    • EAA posts JSON to /api/iac/members with Authorization: Bearer <TOKEN>.

    • The controller validates the token, checks IP allowlist (if defined), and enqueues the record.

    • A log entry “Accepted inbound member…” is recorded.

  2. Queue Processing

    • The queue worker (InboundMemberWorker) runs every minute via system cron.

    • It calls MemberSyncService to upsert the member record:

      • Finds existing user by IAC number, email, or username.

      • Updates changed fields (address, phone, email, expiration date, etc.).

      • Creates a new user if none exists.

      • Assigns the current_member role.

    • Logs each update as “Updated user Jane Doe (12345) fields: …” or “Created new user Jane Doe”.

  3. Retry & Dead-Letter

    • If processing fails, the item is retried up to 5 times.

    • After 5 failures, it is “dead-lettered” (error log entry).
      These can be re-enqueued manually after the issue is fixed.

  4. Lapsed Members

    • The nightly lapsed.php job still controls expiration-based role changes.

    • The inbound API only ensures active/valid members are up to date.


Files & Key Components

File Purpose
iac_members_api.routing.yml Defines /api/iac/members and /api/iac/ping routes.
MemberInboundController.php Handles POSTs, validates token/IP, queues the record.
MemberSyncService.php Applies data to Drupal user entities (upsert logic).
InboundMemberWorker.php Queue worker that processes inbound items; includes retry/dead-letter logic.
iac_members_api.services.yml Registers services (member_validator, member_sync).
settings.php Stores secret token and optional IP allowlist.

Token Management (Bearer Authentication)

Where:
web/sites/default/settings.php

$settings['iac_members_api_token'] = 'very-long-secret-token';

To rotate the token:

  1. Generate a new token:

    python3 - <<'PY' import secrets; print(secrets.token_urlsafe(64)) PY
  2. Add it temporarily as iac_members_api_token_next:

    $settings['iac_members_api_token_next'] = 'new-token-here';
  3. Update the controller’s auth check (already supports comparing multiple tokens).
    Once EAA confirms the switch, remove the old token and rename the new one to iac_members_api_token.

  4. Run drush cr to apply changes.


IP Allowlist (optional)

Also in settings.php:

$settings['iac_members_api_ip_allowlist'] = [  '203.0.113.45',  '198.51.100.0/24', ];
  • If defined, only those IPs may POST.

  • Leave the array empty to allow any source.

  • CIDR notation supported.


Cron & Queue Processing

Location of cron job: webmaster user crontab

* * * * * sudo -u www-data /usr/local/bin/drush -r /usr/local/share/drupal9-prod -l www.iac.org queue:run iac_members_api_inbound 2>&1
  • Runs every minute.

  • Processes any queued items until the queue is empty.

  • Logs output to /var/log/iac_members_queue.log.

To check queue status manually

drush ev '$q=\Drupal::service("queue")->get("iac_members_api_inbound"); echo "Queue size: ".$q->numberOfItems()."\n";' 

To process immediately (manual run)

drush queue:run iac_members_api_inbound

Debugging & Logs

Where to Look

  • Drupal logs: /admin/reports/dblog or

    drush ws --tail 

    Look for iac_members_api channel.

  • System cron log: /var/log/iac_members_queue.log

Common Log Messages

Message Meaning
Accepted inbound member... Record successfully received & queued.
Updated user Jane Doe (12345) fields: ... Successful update.
Created new user Jane Doe New user created.
Retry n for inbound member... Processing failed; will retry.
Dead-lettered inbound member... Gave up after 5 tries — manual review needed.

Manual Inspection Commands

# See user data drush user:information 12345 # View field value (example) drush php:eval '$u=\Drupal\user\Entity\User::load(12345); print_r($u->field_address2->value);' 

Making Edits or Improvements

To modify the logic (e.g., add new field mapping)

  1. Edit /src/Service/MemberSyncService.php.

  2. Map new field in both:

    • processOne() ($row mapping)

    • updateUser() and createUser() (add to field sets)

  3. If adding a new Drupal field (e.g., field_member_type), create it via UI or Drush:

    drush field:create user field_member_type text --label="Member Type" 
  4. Clear caches:

    drush cr

To add new validation rules

Edit /src/Service/MemberValidator.php.


Troubleshooting Quick Reference

Symptom Likely Cause Fix
404 (front page HTML) Route cache not rebuilt drush cr
401 Unauthorized Wrong/missing Bearer token Update token in settings.php
Items never process Cron not running Check crontab -l, /var/log/iac_members_queue.log
Repeated updates for same field NULL/empty string mismatch Confirm normalization in setIfDiff()
“Dead-lettered inbound member…” Permanent error in record Inspect log, fix data or field, re-enqueue via Drush
Class/service not found Typo in iac_members_api.services.yml or cache not cleared Fix YAML, run drush cr -v

Security Summary

  • HTTPS enforced by nginx.

  • Bearer token authentication only (no cookies, no CSRF).

  • Token stored outside config (in settings.php).

  • Optional IP allowlist.

  • Minimal route exposure (POST /api/iac/members only).

  • Constant-time token comparison to prevent timing attacks.


Handy Commands Reference

# Clear caches and rebuild router
drush cr

# Run queue manually
drush qrun iac_members_api_inbound

# Watch logs live
drush ws --tail

# Check queue size
drush ev '$q=\Drupal::service("queue")->get("iac_members_api_inbound"); echo $q->numberOfItems()."\n";'

# Add or test cron job manually
sudo -u www-data drush -r /usr/local/share/drupal9-prod -l www.iac.org qrun iac_members_api_inbound
 


For New Webmasters

  1. If inbound updates stop, first check dblog for 401s or 5xx errors.

  2. If queue backs up, run drush qrun iac_members_api_inbound and tail logs.

  3. If EAA rotates IPs or tokens, update settings.php and drush cr.

  4. To test connectivity, POST a sample JSON record with a known test member ID.

  5. Don’t edit core files — everything lives in web/modules/custom/iac_members_api/.