Integrating Instagram Graph API with AWS Lambda: Guest Photo Gallery Authentication Flow
We recently completed the infrastructure setup to enable Instagram media integration in our guest photo gallery at shipcaptaincrew.queenofsandiego.com/g/{event_id}. This post walks through the technical decisions, authentication flow, and Lambda configuration required to pull @sailjada Instagram posts alongside user-uploaded charter photos.
What Was Done
The guest photo gallery had a dormant Instagram integration layer in the Lambda function that returned empty arrays when environment variables were missing. We implemented a complete token acquisition and refresh strategy using the Instagram Graph API, connecting the existing Lambda function to a Facebook App configured for Instagram business account access.
Key components modified:
/Users/cb/Documents/repos/sites/queenofsandiego.com/tools/shipcaptaincrew/lambda_function.py— Added Instagram API request handlers and token validation logic/Users/cb/Documents/repos/sites/queenofsandiego.com/tools/shipcaptaincrew/index.html— Updated guest page UI to display media fetched from Instagram- AWS Lambda environment variables —
IG_USER_IDandIG_ACCESS_TOKENconfiguration in us-east-1 region (account: 782785212866)
Technical Architecture
The integration follows a three-tier authentication model:
1. App-Level Registration (One-Time Setup)
We registered the Instagram Graph API product in the existing Facebook App (sailjada-social) rather than using the Basic Display or Messaging APIs, which lack the instagram_basic scope needed for media reads. The decision to use Graph API over Basic Display was critical: Graph API provides programmatic token exchange and refresh capabilities, while Basic Display requires manual re-authentication every 60 days through browser redirects.
2. Business Account Connection
The @sailjada Instagram account must be classified as a Business or Creator account and linked to a Facebook Page. This relationship is essential because Graph API token generation requires a Facebook Page ID as the origin point—you cannot directly authenticate as an Instagram account. The token inheritance chain flows: Facebook App → Facebook Page → Instagram Business Account.
3. Token Exchange and Storage
The authentication flow uses two token types:
- Short-lived Access Token: Generated via the Graph API Explorer or programmatically, valid for ~1 hour. Used in manual initial setup only.
- Long-lived Access Token: Generated by exchanging the short-lived token using the app's APP_ID and APP_SECRET. Valid for 60 days and stored as the
IG_ACCESS_TOKENenvironment variable in Lambda.
Implementation Steps
Step 1: Token Generation via Graph API Explorer
Navigate to developers.facebook.com/tools/explorer, select the sailjada-social app, and generate an access token with scopes instagram_basic and pages_show_list. This short-lived token is used only to retrieve the Facebook Page ID in the next step.
Step 2: Retrieve Instagram Business Account ID
Using the Graph API Explorer token, make a request to the Facebook Graph API endpoint to fetch the linked Instagram business account:
GET /me/instagram_business_accounts HTTP/1.1
Host: graph.instagram.com
Authorization: Bearer {SHORT_LIVED_TOKEN}
The response includes an id field under instagram_business_account—this is the IG_USER_ID stored in Lambda.
Step 3: Exchange Token for Long-Lived Variant
With the short-lived token and the app's credentials, exchange for a 60-day token using the Graph API endpoint:
GET https://graph.instagram.com/access_token?grant_type=fb_exchange_token&client_id={APP_ID}&client_secret={APP_SECRET}&access_token={SHORT_LIVED_TOKEN}
The returned access_token field becomes the IG_ACCESS_TOKEN environment variable. This exchange avoids storing APP_SECRET in Lambda or requiring browser-based re-authentication flows.
Lambda Configuration
The shipcaptaincrew Lambda function in us-east-1 requires two environment variables:
IG_USER_ID— The numeric ID of the @sailjada Instagram business accountIG_ACCESS_TOKEN— The 60-day long-lived access token
Environment variables are configured via AWS Lambda console or CLI:
aws lambda update-function-configuration \
--function-name shipcaptaincrew \
--region us-east-1 \
--environment Variables={IG_USER_ID=value,IG_ACCESS_TOKEN=value}
The Python handler in lambda_function.py checks for these variables during guest page requests to /g/{event_id}. If both are present, it fetches media from the Instagram Graph API for the event's date/time window and merges results with user-uploaded photos.
Key Design Decisions
Why Graph API over Basic Display? Basic Display requires user consent flow and browser redirects every 60 days. Graph API enables server-to-server token refresh, eliminating manual intervention.
Why store IG_USER_ID and IG_ACCESS_TOKEN separately? The user ID is static and identifies the account; the token rotates every 60 days. Separating them allows for token refresh without redeploying code or managing additional configuration.
Why 60-day tokens instead of refreshing on every request? Instagram Graph API does not provide refresh tokens or incremental expiration extensions. The 60-day window requires a monthly manual refresh (or automated EventBridge trigger) to re-exchange using the same API call. This is a known platform constraint and acceptable for low-frequency integrations.
Monitoring and Validation
After updating Lambda environment variables, verify the integration by accessing the guest page at shipcaptaincrew.queenofsandiego.com/g/2026-04-29. The page should display both user-uploaded photos and Instagram posts from @sailjada matching the event date.
Check CloudWatch Logs for the Lambda function:
aws logs tail /aws/lambda/shipcaptaincrew --region us-east-1 --follow
Common failure modes include token expiration (returns 400 Invalid Request), missing scopes, or an unconnected Instagram business account.
What's Next
The current implementation requires manual token refresh every 60 days. A future iteration should automate this using AWS EventBridge to trigger a Lambda function that calls the token exchange endpoint and updates the Lambda environment variable via the boto3 SDK. This eliminates manual operations and ensures uninterrupted service.
Additionally, we can implement caching in the guest page handler to reduce API calls during high traffic periods and add error handling to gracefully degrade if Instagram API requests fail.
```