Background
A while ago I was working on a project that consumed the Instagram Legacy API Platform.
To make things easier there was a fantastic library called InstaSharp which wrapped the HTTP calls to the Instagram Legacy API endpoints.
However, Instagram began disabling the Instagram Legacy API Platform and on June 29, 2020, any remaining endpoints will no longer be available.
The replacements to the Instagram Legacy API Platform are the Instagram Graph API and the Instagram Basic Display API.
So, If my project was to continue to work I needed to migrate over to the Instagram Basic Display API before the deadline.
I decided to build and release an open-source library, A wrapper around the Instagram Basic Display API in the same way as InstaSharp did for the original.
Solrevdev.InstagramBasicDisplay
And so began Solrevdev.InstagramBasicDisplay, a netstandard2.0 library that consumes the new Instagram Basic Display API.
It is also available on nuget so you can add this functionality to your .NET projects.
Getting Started
So, to consume the Instagram Basic Display API you will need to generate an Instagram client_id
and client_secret
by creating a Facebook app and configuring it so that it knows your https only redirect_url
.
Facebook and Instagram Setup
Before you begin you will need to create an Instagram client_id
and client_secret
by creating a Facebook app and configuring it so that it knows your redirect_url
. There are full instructions here.
Step 1 - Create a Facebook App
Go to developers.facebook.com, click My Apps, and create a new app. Once you have created the app and are in the App Dashboard, navigate to Settings > Basic, scroll the bottom of page, and click Add Platform.
Choose Website, add your website’s URL, and save your changes. You can change the platform later if you wish, but for this tutorial, use Website
Step 2 - Configure Instagram Basic Display
Click Products, locate the Instagram product, and click Set Up to add it to your app.
Click Basic Display, scroll to the bottom of the page, then click Create New App.
In the form that appears, complete each section using the guidelines below.
Display Name Enter the name of the Facebook app you just created.
Valid OAuth Redirect URIs Enter https://localhost:5001/auth/oauth/ for your redirect_url
that will be used later. HTTPS must be used on all redirect URLs
Deauthorize Callback URL Enter https://localhost:5001/deauthorize
Data Deletion Request Callback URL Enter https://localhost:5001/datadeletion
App Review Skip this section for now since this is just a demo.
Step 3 - Add an Instagram Test User
Navigate to Roles > Roles and scroll down to the Instagram Testers section. Click Add Instagram Testers and enter your Instagram account’s username and send the invitation.
Open a new web browser and go to www.instagram.com and sign in to your Instagram account that you just invited. Navigate to (Profile Icon) > Edit Profile > Apps and Websites > Tester Invites and accept the invitation.
You can view these invitations and applications by navigating to (Profile Icon) > Edit Profile > Apps and Websites
Facebook and Instagram Credentials
Navigate to My Apps > Your App Name > Basic Display
Make a note of the following Facebook and Instagram credentials:
Instagram App ID This is going to be known as client_id
later
Instagram App Secret This is going to be known as client_secret
later
Client OAuth Settings > Valid OAuth Redirect URIs This is going to be known as redirect_url
later
go here for a full-size screenshot
Installation
Now that you have an Instagram client_id
and client_secret
to use we can now create a new dotnet project and add the Solrevdev.InstagramBasicDisplay package to it.
Create a .NET Core Razor Pages project.
dotnet new webapp -n web
cd web
To install via nuget using the dotnet cli
dotnet add package Solrevdev.InstagramBasicDisplay
To install via nuget using Visual Studio / Powershell
Install-Package Solrevdev.InstagramBasicDisplay
App Configuration
In your .NET Core library or application create an appsettings.json
file if one does not already exist and fill out the InstagramSettings
section with your Instagram credentials such as client_id, client_secret and redirect_url as mentioned above.
appsettings.json
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*",
"InstagramCredentials": {
"Name": "friendly name or your app name can go here - this is passed to Instagram as the user-agent",
"ClientId": "client-id",
"ClientSecret": "client-secret",
"RedirectUrl": "https://localhost:5001/auth/oauth"
}
}
Common Uses
Now that you have a .NET Core Razor Pages website and the Solrevdev.InstagramBasicDisplay library has been added you can achieve some of the following common uses.
Get an Instagram User Access Token and permissions from an Instagram user
First, you send the user to Instagram to authenticate using the Authorize
method, they will be redirected to the RedirectUrl
set in InstagramCredentials
so ensure that is set-up correctly in the Instagram app settings page.
Instagram will redirect the user on successful login to the RedirectUrl
page you configured in InstagramCredentials
and this is where you can call AuthenticateAsync
which exchanges the Authorization Code for a short-lived Instagram user access token or optionally a long-lived Instagram user access token.
You then have access to an OAuthResponse
which contains your access token and a user which can be used to make further API calls.
private readonly InstagramApi _api;
public IndexModel(InstagramApi api)
{
_api = api;
}
public ActionResult OnGet()
{
var url = _api.Authorize("anything-passed-here-will-be-returned-as-state-variable");
return Redirect(url);
}
Then in your RedirectUrl
page
private readonly InstagramApi _api;
private readonly ILogger<IndexModel> _logger;
public IndexModel(InstagramApi api, ILogger<IndexModel> logger)
{
_api = api;
_logger = logger;
}
// code is passed by Instagram, the state is whatever you passed in _api.Authorize sent back to you
public async Task<IActionResult> OnGetAsync(string code, string state)
{
// this returns an access token that will last for 1 hour - short-lived access token
var response = await _api.AuthenticateAsync(code, state).ConfigureAwait(false);
// this returns an access token that will last for 60 days - long-lived access token
// var response = await _api.AuthenticateAsync(code, state, true).ConfigureAwait(false);
// store in session - see System.Text.Json code below for sample
HttpContext.Session.Set("Instagram.Response", response);
}
If you want to store the OAuthResponse
in HttpContext.Session
you can use the new System.Text.Json
namespace like this
using System.Text.Json;
using Microsoft.AspNetCore.Http;
public static class SessionExtensions
{
public static void Set<T>(this ISession session, string key, T value)
{
session.SetString(key, JsonSerializer.Serialize(value));
}
public static T Get<T>(this ISession session, string key)
{
var value = session.GetString(key);
return value == null ? default : JsonSerializer.Deserialize<T>(value);
}
}
Get an Instagram user’s profile
private readonly InstagramApi _api;
private readonly ILogger<IndexModel> _logger;
public IndexModel(InstagramApi api, ILogger<IndexModel> logger)
{
_api = api;
_logger = logger;
}
// code is passed by Instagram, the state is whatever you passed in _api.Authorize sent back to you
public async Task<IActionResult> OnGetAsync(string code, string state)
{
// this returns an access token that will last for 1 hour - short-lived access token
var response = await _api.AuthenticateAsync(code, state).ConfigureAwait(false);
// this returns an access token that will last for 60 days - long-lived access token
// var response = await _api.AuthenticateAsync(code, state, true).ConfigureAwait(false);
// store and log
var user = response.User;
var token = response.AccessToken;
_logger.LogInformation("UserId: {userid} Username: {username} Media Count: {count} Account Type: {type}", user.Id, user.Username, user.MediaCount, user.AccountType);
_logger.LogInformation("Access Token: {token}", token);
}
Get an Instagram user’s images, videos, and albums
private readonly InstagramApi _api;
private readonly ILogger<IndexModel> _logger;
public List<Media> Media { get; } = new List<Media>();
public IndexModel(InstagramApi api, ILogger<IndexModel> logger)
{
_api = api;
_logger = logger;
}
// code is passed by Instagram, the state is whatever you passed in _api.Authorize sent back to you
public async Task<IActionResult> OnGetAsync(string code, string state)
{
// this returns an access token that will last for 1 hour - short-lived access token
var response = await _api.AuthenticateAsync(code, state).ConfigureAwait(false);
// this returns an access token that will last for 60 days - long-lived access token
// var response = await _api.AuthenticateAsync(code, state, true).ConfigureAwait(false);
// store and log
var media = await _api.GetMediaListAsync(response).ConfigureAwait(false);
_logger.LogInformation("Initial media response returned with [{count}] records ", media.Data.Count);
_logger.LogInformation("First caption: {caption}, First media url: {url}",media.Data[0].Caption, media.Data[0].MediaUrl);
//
// toggle the following boolean for a quick and dirty way of getting all a user's media.
//
if(false)
{
while (!string.IsNullOrWhiteSpace(media?.Paging?.Next))
{
var next = media?.Paging?.Next;
var count = media?.Data?.Count;
_logger.LogInformation("Getting next page [{next}]", next);
media = await _api.GetMediaListAsync(next).ConfigureAwait(false);
_logger.LogInformation("next media response returned with [{count}] records ", count);
// add to list
Media.Add(media);
}
_logger.LogInformation("The user has a total of {count} items in their Instagram feed", Media.Count);
}
}
Exchange a short-lived access token for a long-lived access token
private readonly InstagramApi _api;
private readonly ILogger<IndexModel> _logger;
public IndexModel(InstagramApi api, ILogger<IndexModel> logger)
{
_api = api;
_logger = logger;
}
// code is passed by Instagram, the state is whatever you passed in _api.Authorize sent back to you
public async Task<IActionResult> OnGetAsync(string code, string state)
{
// this returns an access token that will last for 1 hour - short-lived access token
var response = await _api.AuthenticateAsync(code, state).ConfigureAwait(false);
_logger.LogInformation("response access token {token}", response.AccessToken);
var longLived = await _api.GetLongLivedAccessTokenAsync(response).ConfigureAwait(false);
_logger.LogInformation("longLived access token {token}", longLived.AccessToken);
}
Refresh a long-lived access token for another long-lived access token
private readonly InstagramApi _api;
private readonly ILogger<IndexModel> _logger;
public IndexModel(InstagramApi api, ILogger<IndexModel> logger)
{
_api = api;
_logger = logger;
}
// code is passed by Instagram, the state is whatever you passed in _api.Authorize sent back to you
public async Task<IActionResult> OnGetAsync(string code, string state)
{
// this returns an access token that will last for 1 hour - short-lived access token
var response = await _api.AuthenticateAsync(code, state).ConfigureAwait(false);
_logger.LogInformation("response access token {token}", response.AccessToken);
var longLived = await _api.GetLongLivedAccessTokenAsync(response).ConfigureAwait(false);
_logger.LogInformation("longLived access token {token}", longLived.AccessToken);
var another = await _api.RefreshLongLivedAccessToken(response).ConfigureAwait(false);
_logger.LogInformation("response access token {token}", another.AccessToken);
}
Sample Code
For more documentation and a sample ASP.Net Core Razor Pages web application visit the samples folder in the GitHub repo
Success 🎉
Top comments (0)