Integrating Instagram Graph API into a Lambda-Backed Photo Gallery: Architecture & Implementation

The guest photo page system at shipcaptaincrew.queenofsandiego.com/g/{event_id} aggregates two content sources: user-uploaded charter photos and Instagram posts from the @sailjada account. This post details the technical approach to activate the dormant Instagram Graph API integration within the Lambda function, including authentication flows, token management, and infrastructure decisions.

What Was Done

The Instagram integration in the shipcaptaincrew Lambda function (us-east-1, account 782785212866) was previously non-functional due to missing environment variables: IG_USER_ID and IG_ACCESS_TOKEN. The walkthrough establishes:

  • Correct product configuration in the Meta/Facebook App Dashboard
  • OAuth 2.0 token exchange flow to obtain short-lived and long-lived access tokens
  • Lambda environment variable injection
  • Token refresh strategy for the 60-day long-lived token lifecycle
  • Verification against a live event route: /g/2026-04-29

Technical Details: OAuth 2.0 Token Flow

Step 1: Product Configuration

The Problem: The initial app setup used the "Manage Messaging" use case, which grants DM-related scopes but excludes the instagram_basic scope required to read media metadata.

The Solution: Add the Instagram Graph API

  • Navigate to developers.facebook.com/apps
  • Select the sailjada-social application
  • Click Add Product (left sidebar, near bottom)
  • Search for and select Instagram Graph API (distinct from Basic Display and Messaging APIs)

Why this approach: The Graph API provides programmatic access to media insights and post metadata. The Messaging API is designed for direct messages only and lacks the scope breadth needed for media aggregation.

Step 2: Account Linking

The @sailjada Instagram account must be configured as a Business or Creator account and linked to a Facebook Page. This relationship is required by Meta's architecture—Instagram Graph API access is granted through the associated Facebook Page, not directly through the Instagram account.

Within the Instagram Graph API product configuration:

  • Go to API setup with Instagram login
  • Click Add Instagram account
  • Authenticate as @sailjada

Step 3: Short-Lived Token Generation

Short-lived tokens are generated via the Graph API Explorer and are valid for approximately 1 hour. They're used to bootstrap the long-lived token exchange.

Process:

  • Visit developers.facebook.com/tools/explorer
  • Select sailjada-social app from the dropdown
  • Click Generate Access Token
  • Select the Facebook Page associated with @sailjada
  • Grant scopes: instagram_basic, pages_show_list
  • Copy the resulting access token (valid ~1 hour)

Step 4: Retrieve IG_USER_ID

The Instagram Business Account ID must be extracted from the Facebook Page's linked accounts. Two API calls are required:

curl -s "https://graph.instagram.com/v18.0/me/accounts?fields=instagram_business_account&access_token=TOKEN" \
  | jq '.data[0].instagram_business_account.id'

This returns the Facebook Page ID. Then:

curl -s "https://graph.instagram.com/v18.0/{PAGE_ID}?fields=instagram_business_account&access_token=TOKEN" \
  | jq '.instagram_business_account.id'

The id field in the response is IG_USER_ID—the unique identifier for the @sailjada business account in Instagram's system.

Step 5: Long-Lived Token Exchange

Short-lived tokens expire after ~1 hour. A long-lived token (valid 60 days) is obtained by exchanging the short-lived token with the app credentials:

curl -s "https://graph.instagram.com/access_token?grant_type=ig_refresh_token&access_token=SHORT_LIVED_TOKEN" \
  -d "client_id=APP_ID" \
  -d "client_secret=APP_SECRET" \
  | jq '.access_token'

Why this flow: Long-lived tokens reduce the need for frequent re-authentication and allow unattended operation. The 60-day window requires a refresh strategy (covered below).

Infrastructure: Lambda Configuration

Once IG_USER_ID and IG_ACCESS_TOKEN are obtained, they are injected into the Lambda function environment:

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

The Lambda function (located in the shipcaptaincrew function, us-east-1 region, account 782785212866) checks for these environment variables at runtime. When present, it queries the Instagram Graph API endpoint:

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

Results are filtered by timestamp to match the event date window (e.g., posts within 24 hours of the event date) and merged with approved guest photos in the response payload.

Token Refresh Strategy

Key Decision: Rather than implementing a complex EventBridge-triggered refresh Lambda, the initial approach is manual monthly refresh. The long-lived token endpoint can be called identically to Step 5, using the current token to obtain a new one with a fresh 60-day window.

Recommended automation (future): An EventBridge rule triggering a dedicated Lambda function (e.g., instagram-token-refresh) weekly, which invokes the token exchange API and updates the shipcaptaincrew function's environment variables via update-function-configuration. This can be stored in AWS Secrets Manager for safer credential rotation.

Key Decisions

  • Graph API over Basic Display: Basic Display limits fields to a minimal set; Graph API provides broader metadata and supports programmatic filtering.
  • Environment variables over Secrets Manager (initial): For rapid deployment, environment variables suffice. Production should migrate credentials to Secrets Manager with Lambda IAM policies.
  • 60-day token cycle: