DEV Community

John Smith
John Smith

Posted on • Originally published at solrevdev.com on

Instagram Basic Display API

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.

Step 1a - Create a Facebook App

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 1b - Create a Facebook App

Step 2 - Configure Instagram Basic Display

Click Products, locate the Instagram product, and click Set Up to add it to your app.

Step 2a - Configure Instagram Basic Display

Click Basic Display, scroll to the bottom of the page, then click Create New App.

Step 2b - Configure Instagram Basic Display

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.

Step 3a - Add an Instagram Test User

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.

Step 3b - Add an Instagram Test User

You can view these invitations and applications by navigating to (Profile Icon) > Edit Profile > Apps and Websites

Step 3c - Add an Instagram Test User

Facebook and Instagram Credentials

Navigate to My Apps > Your App Name > Basic Display

Navigate to My App

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

Facebook and Instagram Credentials 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)