Integrating Instagram Graph API into a Lambda-Based Photo Gallery: Token Generation and Long-Lived Access

What Was Done

We activated Instagram Graph API integration for the shipcaptaincrew Lambda function to display @sailjada Instagram posts alongside guest-uploaded charter photos on the guest gallery page at shipcaptaincrew.queenofsandiego.com/g/{event_id}. The integration had been dormant in the codebase—returning an empty array when environment variables were missing. This walkthrough documents the exact steps to generate and refresh long-lived access tokens, configure Lambda environment variables, and verify the integration works end-to-end.

Technical Details

Product Configuration in Facebook App Dashboard

The initial blocker was a product misconfiguration. The app sailjada-social (in Facebook App Dashboard at developers.facebook.com/apps) had the Instagram Messaging API product added, which grants scopes for direct message handling but not for reading media. This is a critical distinction:

  • Instagram Messaging API: Scopes like instagram_manage_messages, instagram_manage_insights—used for bot interactions and DM replies.
  • Instagram Graph API: Scopes like instagram_basic, instagram_business—used for reading media, captions, and engagement metrics.

We added the correct product by navigating to:

App Dashboard → Add Products → Instagram Graph API (select "Instagram Graph API," not Basic Display or Messaging)

Once added, the product appears in the left sidebar under "Instagram Graph API" and becomes the surface for API setup.

Account Linking and Token Generation Flow

Instagram Graph API requires that the Instagram account be linked to a Facebook Business or Creator Page. The @sailjada account is a Creator account, and it must be associated with a Facebook Page for the API to access media metadata. We performed the linking inside the app dashboard:

Instagram Graph API → API setup with Instagram login → Add Instagram account → (log in as @sailjada)

After linking, we generated a short-lived access token (valid for ~1 hour) using the Graph API Explorer:

  1. Navigate to developers.facebook.com/tools/explorer
  2. Select app: sailjada-social
  3. Click "Generate Access Token"
  4. Select the Facebook Page linked to @sailjada
  5. Request scopes: instagram_basic, pages_show_list

The short-lived token is used to bootstrap the process. Two subsequent API calls retrieve the Instagram User ID and exchange the token for a long-lived version (60 days).

Retrieving the Instagram User ID

With the short-lived token, we call the Graph API to fetch the Facebook Page ID, then extract the linked Instagram Business Account ID:

curl -s "https://graph.facebook.com/v18.0/me?fields=instagram_business_account&access_token=SHORT_LIVED_TOKEN"

The response includes the page ID. Using that page ID, we fetch the Instagram Business Account:

curl -s "https://graph.facebook.com/v18.0/{PAGE_ID}?fields=instagram_business_account&access_token=SHORT_LIVED_TOKEN"

The instagram_business_account.id from the response is the IG_USER_ID value we store as a Lambda environment variable.

Long-Lived Token Exchange

The short-lived token is then exchanged for a long-lived access token (valid for 60 days) using the app credentials and the short-lived token:

curl -s "https://graph.facebook.com/oauth/access_token?grant_type=fb_exchange_token&client_id=APP_ID&client_secret=APP_SECRET&fb_exchange_token=SHORT_LIVED_TOKEN"

The returned access_token is the IG_ACCESS_TOKEN stored in the Lambda environment.

Infrastructure Changes

Lambda Function Configuration

The shipcaptaincrew Lambda function (region: us-east-1, account: 782785212866) required environment variable updates. These variables control whether the Instagram integration is active and which account to query:

  • IG_USER_ID – The Instagram Business Account ID (numeric string)
  • IG_ACCESS_TOKEN – The long-lived access token (refreshed monthly)

The update command structure is:

aws lambda update-function-configuration \
  --function-name shipcaptaincrew \
  --region us-east-1 \
  --environment Variables="{IG_USER_ID=value,IG_ACCESS_TOKEN=value}"

Upon execution, Lambda creates a new function version; the deployment is immediate. The function's existing event sources (API Gateway routes for /g/{event_id}) automatically route traffic to the updated configuration.

Code Path References

The Lambda code that consumes these variables is embedded in the handler. When both variables are present and non-empty, the function queries Instagram's Media Edges endpoint during the guest gallery render. The query path is:

GET https://graph.instagram.com/v18.0/{IG_USER_ID}/media?fields=id,caption,media_type,timestamp&access_token={IG_ACCESS_TOKEN}

Posts are filtered by timestamp to match the event date window (e.g., /g/2026-04-29 matches posts within 24 hours of that date).

Key Decisions

Why Long-Lived Tokens Instead of Short-Lived Tokens

Short-lived tokens expire in ~1 hour, requiring a refresh mechanism on every Lambda invocation. Long-lived tokens (60 days) reduce external API calls and complexity. The trade-off is that they require a monthly refresh job to maintain continuous operation without manual intervention.

Why Not Use Basic Display API?

Instagram's Basic Display API is simpler but doesn't return timestamp metadata, making it impossible to correlate posts with specific event dates. Graph API provides timestamp fields necessary for accurate event-based photo filtering.

Why Store Credentials in Lambda Environment Variables

Environment variables are encrypted at rest using the Lambda service default KMS key. For production systems handling public data (Instagram posts are public), this provides sufficient security with operational simplicity. Sensitive tokens are never logged or exposed in function code.

What's Next

A monthly refresh job should be implemented to re-exchange the long-lived token before expiration. This can be achieved via EventBridge scheduled rule (cron: 0 0 1 * ? * for first of each month) triggering a Lambda function that calls the exchange endpoint and updates shipcaptaincrew's environment variables.

Verification is performed by navigating to shipcaptaincrew.queenofsandiego.com/g/2026-04