GET /auth/me

Generating System-Level JSON Web Token (JWT)

API Users will need to generate a JSON Web Token (JWT) to use for system-level authentication to the Dataset Exchange API. This JWT is required for generating time-limited Client Data Access (CDA) tokens.

To generate a System Level JWT you will need your App's Private Key. Your Private Key can be found in App dashboard in the MIG Console.

📘

You can find our Python client library here for generating a System-Level JWT.

Node Gist for Generating a System-Level JWT:

const fs = require("fs");
const jwt = require("jsonwebtoken");

/** Use an app ID and private key to authenticate to MIG's proxy API service */
const authenticateToMIGProxyAPI = async (
  appId: string,
  privateKeyPath: string
) => {
  const privateKey = fs.readFileSync(privateKeyPath, "utf8");

  // Confirm that appId is a valid uuid
  const isValidUUID = (appId: string) => /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(appId);
  if (!isValidUUID){
    throw new Error("App ID is invalid.");
  }

  // Create a new JWT token using the app ID as issuer and private key
  const jwtToken = jwt.sign({ MovementAppId: appId }, privateKey, {
    issuer: appId,
    audience: "movementconsole",
    expiresIn: "1h",
    notBefore: "0s",
    algorithm: "RS256",
  });

  // The fetch will log the response from the API if successful
  const data = await fetch(
    "https://app.movementinfrastructure.org/api/v1/auth/me",
    {
      method: "GET",
      headers: {
        "Content-Type": "application/json",
        Authorization: `Bearer ${jwtToken}`,
      },
    }
  )
    .then((response) => {
      if (response.ok) {
        return response.json();
      } else {
        throw new Error("Error authenticating to the MIG Proxy API.");
      }
    })
    .then((data) => {
      return data;
    })
    .catch((error) => {
      throw new Error(error.message);
    });
  return data;
};

// Export the function for use
export { authenticateToMIGProxyAPI };

C# Gist for Generating System-Level JWT

using System.Net.Http.Headers;
using System.Net.Http.Json;
using System.Security.Claims;
using System.Security.Cryptography;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.IdentityModel.JsonWebTokens;
using Microsoft.IdentityModel.Tokens;

namespace MinervaAuthExample;

class Program
{
    const int RsaKeySize = 2048;
    
    static async Task Main(string[] args)
    {
        if (args.Length < 2)
        {
            throw new ArgumentException("App ID and private key file path must both be specified.");
        }
        
        var appIdString = args[0];
        
        if(!Guid.TryParse(appIdString, out var appId))
        {
            throw new ArgumentException("App ID must be a GUID");
        }
        
        var privateKeyFilePath = args[1];
        var baseUrl = args.Length > 2 ? args[2] : "movementinfrastructure.org";
        
        // set up HttpClient
        var builder = WebApplication.CreateBuilder(args);
        builder.Services.AddHttpClient();
        var serviceProvider = builder.Build();
        var client = serviceProvider.Services.GetService<HttpClient>();

        // get private key contents from .pem file provided as argument
        var privateKeyPem = File.ReadAllText(privateKeyFilePath);
        
        // sign a JWT for the new app using its private key
        var jwt = CreateMinervaSystemToken(privateKeyPem, appId: appId);

        // add as a bearer token
        client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", jwt);

        // get authorization context info from API
        var response = await client.GetAsync(baseUrl + "api/v1/auth/me");
        var whoAmI = await response.Content.ReadFromJsonAsync<WhoAmIDto>();

        // print auth information
        Console.WriteLine(whoAmI);
    }
    
    public record WhoAmIDto(int UserId, int TenantId, Guid? AppId, string UserName, string Email);

    public static string CreateMinervaSystemToken(string privateKeyPem, Guid appId)
    {
        var now = DateTime.UtcNow;
        
        // use the built-in structured tooling to populate and sign JWTs
        var tokenHandler = new JsonWebTokenHandler();

        // create an RSA container to hold the private key
        using var rsa = RSA.Create(RsaKeySize);

        // import the private key from the PEM input and pass to the JWT signature
        rsa.ImportFromPem(privateKeyPem);
        var signingCredentials =
            new SigningCredentials(new RsaSecurityKey(rsa), SecurityAlgorithms.RsaSha256);

        var serializedAppId = appId.ToString("D");

        // create App ID claim to add to identity
        var claims = new[] { new Claim("MinervaAppId", serializedAppId) };

        var tokenDescriptor = new SecurityTokenDescriptor
        {
            Issuer = serializedAppId,
            Audience = "movementconsole",
            IssuedAt = now,
            NotBefore = now,
            Expires = now.AddHours(1),
            Subject = new ClaimsIdentity(claims),
            SigningCredentials = signingCredentials
        };

        // serialize and sign the JWT, with the signature embedded in the result string
        return tokenHandler.CreateToken(tokenDescriptor);
    }

}

Generating Client Data Access (CDA) JSON Web Token (JWT)

Your system-level JWT should be used to access the GET and POST endpoints required to generate a scoped, time-limited Client Data Access (CDA) token.

  1. After generating a system-level JWT, you should call the GET /apps/me/installations endpoint. This endpoint will return a list of available Workspaces that have "connected" to or installed your App. You should use the Workspace ID and Workspace Key provided to you by the Campaign or Organization you're working with to determine the installationId.
  2. You will use the installationId to hit the POST /auth/clientTokenendpoint and generate a Client Data Access Token for accessing the associated datasets. Client Data Access tokens are scoped to an individual Workspace and expires in 1 hour.
  3. Done! You can submit and/or retrieve datasets using your CDA JWT.

Do not share your secret API keys in publicly accessible areas such as GitHub, client-side code, etc. All API requests must be made over HTTPS. See errors for examples and more information.

For more information on how you or your users can Connect to your App and where to find the Workspace ID and Workspace Key, please check out this guide!