Integrating Instagram Graph API with AWS Lambda: Adding Social Media Context to Guest Photo Pages
What Was Done
We activated dormant Instagram Graph API integration in the shipcaptaincrew Lambda function (us-east-1, account 782785212866) to display @sailjada Instagram posts alongside guest-uploaded charter photos on the guest photo page system at shipcaptaincrew.queenofsandiego.com/g/{event_id}. The infrastructure was already in place but non-functional due to missing environment variables. This post walks through the token generation, Lambda configuration, and verification process.
Technical Details: Token Generation Strategy
Instagram Graph API requires a two-stage token lifecycle: short-lived tokens (valid for ~1 hour) must be exchanged for long-lived tokens (valid for 60 days). Rather than manually regenerating tokens monthly, we implemented a sustainable refresh pattern that can be automated via EventBridge if needed.
Stage 1: Setting Up the App Product
The initial blocker was product misconfiguration in the Facebook App Dashboard. The app had Instagram Messaging added (from an earlier implementation attempt), which grants DM-related scopes but not the instagram_basic scope required to read media:
- Navigate to
developers.facebook.com/apps - Select the
sailjada-socialapp - Click Add Product in the left sidebar
- Search for and select Instagram Graph API (distinct from Instagram Basic Display or Instagram Messaging)
- Complete the setup flow
This product addition is a one-time operation and automatically appears in the app dashboard sidebar.
Stage 2: Connecting the Instagram Business Account
The @sailjada account must be a Business or Creator account linked to a Facebook Page (verified beforehand). From the Instagram Graph API product settings:
- Navigate to API Setup
- Click Add Instagram Account
- Authenticate as @sailjada
- Authorize the app to access the account's media endpoints
This creates the authorization link between the app and the Instagram business account.
Stage 3: Generating Short-Lived Token
Using the Facebook Graph API Explorer at developers.facebook.com/tools/explorer:
- Select
sailjada-socialfrom the app dropdown - Click Generate Access Token
- Select the Facebook Page linked to @sailjada from the account picker
- Ensure scopes include
instagram_basicandpages_show_list - Copy the resulting short-lived token (valid ~1 hour)
Stage 4: Retrieving IG_USER_ID
The Instagram business account ID is nested within the Facebook Page structure. Two API calls extract it:
curl -s "https://graph.instagram.com/v18.0/{PAGE_ID}?fields=instagram_business_account&access_token={SHORT_LIVED_TOKEN}" | jq .
Record the PAGE_ID from this response, then query the Instagram business account:
curl -s "https://graph.instagram.com/v18.0/{PAGE_ID}?fields=instagram_business_account&access_token={SHORT_LIVED_TOKEN}" | jq '.instagram_business_account.id'
The returned id field is your IG_USER_ID. This value is account-specific and remains static across token refreshes.
Stage 5: Exchanging for Long-Lived Token
Convert the short-lived token to a long-lived token (60-day expiry) using the app credentials:
curl -s "https://graph.instagram.com/v18.0/access_token?grant_type=ig_exchange_token&client_id={APP_ID}&client_secret={APP_SECRET}&access_token={SHORT_LIVED_TOKEN}" | jq .
The response contains an access_token field with extended validity. This is your IG_ACCESS_TOKEN.
Infrastructure Changes
Lambda Environment Variables
Update the shipcaptaincrew Lambda function configuration in us-east-1:
aws lambda update-function-configuration \
--function-name shipcaptaincrew \
--region us-east-1 \
--environment Variables="{IG_USER_ID=,IG_ACCESS_TOKEN=}"
These variables are referenced in the Lambda handler code (exact function path varies with deployment, typically within the photo-fetching logic that currently returns an empty array when these vars are absent).
Token Refresh Strategy
Long-lived tokens expire after 60 days. Two approaches:
- Manual refresh: Re-run the token exchange call every 58-59 days and update Lambda environment via AWS CLI or Console
- Automated refresh: Create an EventBridge rule triggering a Lambda function every 55 days to exchange the current token for a fresh one and update the parent Lambda's environment (requires IAM permissions for
lambda:UpdateFunctionConfiguration)
For initial deployment, manual refresh is sufficient. Document the token generation date in your deployment notes or a private wiki.
Key Architectural Decisions
Why Not Direct Credentials in Code?
The Lambda function never stores APP_ID or APP_SECRET in code or environment. These values remain in the Facebook App Dashboard and are only used during the initial token exchange, which happens in your local shell or a secured CI/CD pipeline. This limits the blast radius of accidental credential exposure.
Why Long-Lived Tokens?
Short-lived tokens expire hourly, requiring a new generation every Lambda invocation. Long-lived tokens eliminate this overhead and are sufficient for read-only media access. The 60-day expiry is a Facebook limitation; refresh cadence is manageable via calendar reminders or automation.
Why Separate IG_USER_ID and IG_ACCESS_TOKEN?
The user ID is static; the token is ephemeral. Separating them allows token rotation without code changes. The Lambda function queries Instagram media using the pattern /v18.0/{IG_USER_ID}/media, keeping the endpoint structure stable across refreshes.
Verification
After Lambda environment update propagates (usually within seconds):
- Navigate to
shipcaptaincrew.queenofsandiego.com/g/2026-04-29(or another known event date) - Open browser DevTools → Network tab
- Look for API responses that previously returned empty arrays for Instagram posts
- Verify that posts from @sailjada around the event timestamp now appear alongside guest photos
What's Next
Consider implementing automated token refresh via EventBridge to eliminate manual intervention. This requires a secondary Lambda function with appropriate