Scoped API Keys

Introduction

Uplynk has traditionally secured their APIs with a user-generated token that utilized API keys that are viewable in the Uplynk CMS. This technique is not very flexible, meaning that any API key generated by a user could access all Uplynk functionality, regardless of whether the user of the API key needs this access.

Scoped API Keys allows specific API functionality to be limited to those individuals or systems that need it. Uplynk’s traditional API integration keys and the new Scoped API Keys will coexist for the foreseeable future.

How Are Scoped API Keys Implemented?

To implement Scoped API Keys, Uplynk moved to using a more modern and standardized way of doing API authentication using XAuth with JSON Web Tokens (JWTs).

The Uplynk CMS allows for both the creating and testing of JWTs to avoid having to debug API key access while developing code.

Limitations

Scoped API keys cannot be used for creating playback tokens. Scoped API keys are meant purely for the REST calls to the system itself, rather than playback.

XAuth Authentication

XAuth API authentication uses XAuth keys and JSON Web Tokens (JWTs).

XAuth keys:

  • An XAuth key is created within the Uplynk CMS and contains public and private encryption keys, the allowed scope (permissions) for using APIs, the ability to not allow tokens to be used after a certain time, Key ID, and other information.
  • The scope of an XAuth key allows for implementing the Principle of Least Privilege (POLP) methodology.
  • XAuth keys are used to generate ES256 (Elliptic Curve Digital Signature Algorithm) encrypted JWTs for API authentication.
  • In the Uplynk CMS, XAuth keys are called “Scoped API Keys”.

JWTs:

  • A JWT is sent with the API request in a new request header called X-Auth-Uplynk-JWT.
  • When Uplynk receives an API request with a JWT, it validates the information in the token against the XAuth key (Scoped API Key) in the CMS to allow or disallow access.

Uplynk decided to use XAuth authentication to allow a user to:

  • Authenticate using JWTs which have standard libraries for every programming language.
  • Create key revisions to allow for the adjustment of permissions given for an API user.
  • Have keys that expire after a short time for temporary access.
  • Quickly activate, deactivate, or revise keys to allow or prevent access to API endpoints.
  • Utilize the principal of least privilege (POLP) to control functionality access via API.
  • Create user-specific tokens.
  • Create tokens that are only valid during a specific time window.

Uplynk API Scopes

Uplynk allows users to give different API permissions for the following functional areas:

  • Ads
  • Assets
  • Channels
  • Clipping
  • Ingest
  • Linear Playlists
  • Live Events
  • Workspace

Each functional area may have subareas and read/write control. Generally, API permissions should be as limited as possible, following POLP.

The table below shows all of the different API scopes:

ScopeScope PermissionsScope Description
Adsvideo.services.adsAllows read and write access for ad APIs
Ads - Readvideo.services.ads:readAllows read access for ad APIs
Ads - Writevideo.services.ads:writeAllows write access for ad APIs
Assetsvideo.services.assetsAllows read and write access for APIs used for managing assets and content libraries
Assets - Readvideo.services.assets:readAllows read access for asset APIs
Assets - Writevideo.services.assets:writeAllows write access for asset APIs
Assets - Libraries - Readvideo.services.assets.libraries:readAllows read access for APIs which deal with content libraries
Assets - Libraries - Writevideo.services.assets.libraries:writeAllows write access for APIs which deal with content libraries
Assets - Libraries – Shared Users Adminvideo.services.assets.libraries.users:adminAllows access to API functionality to control which users can access this account’s content libraries
Channelsvideo.services.channelsAllows read and write access for APIs used for managing linear channels
Channels - Readvideo.services.channels:readAllows read access for APIs used for managing linear channels
Channels - Writevideo.services.channels:writeAllows write access for APIs used for managing linear channels
Channels - Blackouts - Readvideo.services.channels.blackout:readAllows read access for APIs used for managing blackouts on linear channels
Channels - Blackouts - Writevideo.services.channels.blackout:writeAllows write access for APIs used for managing blackouts on linear channels
Channels - Schedules - Readvideo.services.channels.schedule:readAllows read access for APIs used for the Channel Scheduler
Channels - Schedules - Writevideo.services.channels.schedule:writeAllows write access for APIs used for the Channel Scheduler
Clippingvideo.services.clippingAllows read and write access for APIs used for managing clipping
Clipping - Readvideo.services.clipping:readAllows read access for APIs used for managing clipping
Clipping - Writevideo.services.clipping:writeAllows write access for APIs used for managing clipping
Ingestvideo.services.ingestAllows read and write access for APIs used for managing ingest regardless of method
Ingest - Slicer - Readvideo.services.ingest.slicer:readAllows read access for APIs used for controlling Slicers, either on-premise or cloud-based
Ingest - Slicer - Writevideo.services.ingest.slicer:writeAllows write access for APIs used for controlling Slicers, either on-premise or cloud-based
Ingest - Slicer - Operatorvideo.services.ingest.slicer:opsAllows on-premise Slicers to use Scoped API Key tokens in their configuration files. This is a Beta feature and must be enabled by the Uplynk support team.
Ingest - Cloud Slicers Live - Readvideo.services.ingest.cloudslicer.live:readAllows read access for APIs used for controlling cloud-based Slicers for linear
Ingest - Cloud Slicers Live - Writevideo.services.ingest.cloudslicer.live:writeAllows write access for APIs used for controlling cloud-based Slicers for linear
Ingest - Cloud Slicers VOD - Readvideo.services.ingest.cloudslicer.vod:readAllows read access for APIs used for controlling cloud-based Slicers for VOD
Ingest - Cloud Slicers VOD - Writevideo.services.ingest.cloudslicer.vod:writeAllows write access for APIs used for controlling cloud-based Slicers for VOD
Ingest - Failover Groups - Readvideo.services.ingest.failover-groups:readAllows read access for APIs used for controlling Slicer Failover
Ingest - Failover Groups - Writevideo.services.ingest.failover-groups:writeAllows write access for APIs used for controlling Slicer Failover
Linear Playlistsvideo.services.linear-playlistsAllows read and write access for APIs used for managing linear playlists
Linear Playlists - Readvideo.services.linear-playlists:readAllows read access for APIs used for managing linear playlists
Linear Playlists - Writevideo.services.linear-playlists:writeAllows write access for APIs used for managing linear playlists
Linear Playlists - Smartstartvideo.services.linear-playlists.smartstart:writeAllows write API access for Smartstart functionality which is a specialized version of a virtual linear playlist
Live Eventsvideo.services.leAllows read and write access for APIs used for managing live events
Live Events - Readvideo.services.le:readAllows read access for APIs used for managing live events
Live Events - Writevideo.services.le:writeAllows write access for APIs used for managing live events
Live Events - Opsvideo.services.le.opsAllows API access for getting the list of other accounts who are authorized to operate live events
Workspacevideo.services.workspaceAllows read and write access for APIs used for general system settings
Workspace - Scoped API Keys - Readvideo.services.workspace.api-key:readAllows read access for APIs used for managing Scoped API Keys
Workspace - Scoped API Keys - Writevideo.services.workspace.api-key:writeAllows write access for APIs used for managing Scoped API Keys
Workspace - Scoped API Keys - Adminvideo.services.workspace.api-key:adminAllows administrative access for APIs used for managing Scoped API Keys

Creating a Scoped API Key

Scoped API Keys have both public and private encryption keys which need to be kept by the user in what they consider a secure location.

After Scoped API Key creation, a user can download this key information in Privacy Enhanced Mail (PEM) format or as plaintext in an .env file. PEM is the most common format for storing cryptographic key information. The Uplynk sample code for using Scoped API Keys uses .env files.

There is no limit to the number of Scoped API Keys allowed so it is recommended to have more keys that are limited in scope than less keys than have more scope in case a key is compromised.

To create a Scoped API Key:

  1. Go to Settings tab in CMS
  2. Click Scoped API Keys tab
  3. Click + Key

  1. Enter a name for the Scoped API Key
  2. Enter a description for the Scoped API Key

  1. Click on Scopes tab
  2. Select the desired permissions for the Scoped API Key

  1. Click on Advanced tab
  2. If desired, enter a domain to limit key requests from that domain
  3. If desired, enter an expiration date for the Scoped API Key
  4. Click Create

To save the key information:

  1. Click on Download PEM File to save the public and private encryption keys in a .pem file
  2. Click on Download .env File to save the public and private encryption keys in cleartext
  3. After downloading, click the checkbox
  4. Click Close

Updating a Scoped API Key

Existing Scoped API Keys can be updated, usually to expand or reduce the scope of allowed access. Multiple revisions of a Scoped API Key can be active at the same time to avoid issues where a key may just stop working for a user.

Individual revisions of a Scoped API Key can be independently activated or deactivated. Individual revisions of a Scoped API Key cannot be deleted – they can just be deactivated.

Up to three active versions of a Scoped API Key are allowed.

In the following example, the scope of a Scoped API Key will be updated to add more access:

  1. Go to Settings tab in CMS
  2. Click Scoped API Keys tab
  3. Click on the key to edit

  1. Click Scopes tab

  1. Click on Ads (or any desired scope) to enable permission to use these APIs
  2. Click Create Revision

To save the updated key information:

  1. Click on Download PEM File to save the public and private encryption keys in a .pem file
  2. Click on Download .env File to save the public and private encryption keys in cleartext
  3. After downloading, click the checkbox
  4. Click Close

Deactivating a Scoped API Key Revision

  1. Go to Settings tab in CMS
  2. Click Scoped API Keys tab
  3. Click on the key to edit

  1. Click on the revision to deactivate (e.g., 1)

  1. Click Deactivate and the revision number will turn red
  2. Click Close

Reactivating a Scoped API Key Revision

  1. Go to Settings tab in CMS
  2. Click Scoped API Keys tab
  3. Click on the key to edit

  1. Click on the revision to reactivate (e.g., 1)

  1. Click Activate and the revision number will turn green
  2. Click Close

Contents of the JWT

The JWT which is included in REST API calls to Uplynk is included in the X-Auth-Uplynk-Jwt header. The JWT is created using the information contained in either the .env file or .pem file downloaded when creating an API key.

There is a header and a payload in the JWT, with the header containing information on the JWT and the payload containing “claims”. Claims are essentially name/value pairs containing the entitlements allowed for a user as well as additional metadata.

Examples of claims include the token expiration time, the allowed scopes, and the timestamp at which the token was created. There are both required and optional claims.

Header

  • kid - (required) - Key ID
  • alg - (required) - The algorithm used for encoding/decoding the key, default is "ES256"
  • typ - (required) - The key type, default is "JWT"

Payload

  • Required:
    • exp - timestamp - Token Expiration (not used when creating a net token)
    • iat - timestamp - Issued at Time (Timestamp at which the token was created)
    • sub - string - Subject (Owner ID)
    • scp - string array - Scope (String list of request scopes)
  • Optional:
    • iss - string - Issuer (domain that the token originated from)
    • nbf - timestamp - Not Before Time (token will not be valid until after this time)
    • net - boolean - Non-Expirable Token (Token will not expire, do not include the exp claim when set to True)
    • msg - object - used when interacting with api2 endpoints that require data

Python Sample Code

Prerequisites

  • Sample code for Python is for Python 3.9 and later
  • Need to install the following modules via pip3 install:
    • Pyjwt (Version 2.8.0 or later)
    • python-dotenv (Version 0.14.0 or later)
    • Requests (Version 2.32.3 or later)
  • Rename the .env file downloaded from the Uplynk CMS to be “.env” and this file must reside in the same directory as the sample code

Required Files

Three files are required for running the code utilizing XAuth authentication with JWTs:

  • uplynk_api.py
  • demo.py
  • The .env file containing the information needed to build the JWT sent with REST API calls to Uplynk

Using the uplynk_api.py Module

The uplynk_api.py module provides a class called UplynkApi with a functions used for calling Uplynk APIs. For v2 APIs, there is a Call function similar to that used in Uplynk documentation for v2 APIs. For v4 APIs, there are the following functions:

  • Get
  • Post
  • Put
  • Patch
  • Delete

If the JWT sent in the API call does not have the proper scope, an error will be returned indicating this.

The uplynk_api.py module is at:

Sample Code (demo.py)

The sample code shows the initialization of the UplynkApi class as well as v2 and v4 API calls.
The parameters for using UplynkApi are in the .env file which has to be named “.env”.

This is the demo.py code:

import sys
from dotenv import load_dotenv
from pprint import PrettyPrinter
from os import getenv

from uplynk_api import UplynkApi

pp = PrettyPrinter().pprint

if not(load_dotenv()):
    pp("ERROR: .env file not found!")
    sys.exit(-1)

PRIVATE_B64 = getenv("PRIVATE_B64")
KID = getenv("KID")
SUB = getenv("SUB")
SCP = getenv("SCP").split(",")
ROOT_URL = getenv("ROOT_URL")

ul_api = UplynkApi(SUB, KID, PRIVATE_B64, SCP, host=ROOT_URL)

# Call v2 apis
pp(ul_api.Call("/api2/cloudslicer/jobs/list"))
pp(ul_api.Call("/api2/library/get", id="584f328723e043849eb46420441d92c0"))

# Call v4 apis
pp(ul_api.Get("/api/v4/libraries"))
pp(ul_api.Get("/api/v4/failover-groups"))

Running the Sample Code

The files uplynk_api.py, demo.py, and .env need to be in the same directory. The prerequisite Python version and libraries need to be installed.

Type the following at the command-prompt followed by :
$python3 demo.py

The output of the sample code will look similar to that below. The actual results depends on the the contents of your Uplynk account.

Token Debugger

The Token Debugger allows for viewing and modifying the information contained in the JWT used for authentication. Using the Token Debugger is not required for using Uplynk’s XAuth API authentication and is provided as an advanced feature.

To use the Token Debugger:

  • Go to Settings tab in CMS
  • Click Scoped API Keys tab
  • Click on Token Debugger

  1. While debugging your code, capture the JWT contained in the X-Auth-Uplynk-Jwt header being sent with the Uplynk API call
  2. Paste in the JWT contained in the X-Auth-Uplynk-Jwt header being sent with the Uplynk API call
  3. Click Read Token

  1. Observe the decoded JWT

Creating a Test JWT

  1. Go to Settings tab in CMS
  2. Click Scoped API Keys tab
  3. Click on Token Debugger

  1. Drag and drop an .env file here or use Browse Files to browse for it

  1. Observe the token to use in the X-Auth-Uplynk-Jwt header
  2. If desired, the scope (scp) of the token can be edited
  3. If desired, net can be selected to make the token never expire
  4. If desired, the token can be made to take effect at a certain date and time using nbf
  5. Observe that the token was updated with any edits and that the expiration is five minutes after the last edit if net not used

Using the Slicer with a JWT (Beta)

A JWT can be used with the Slicer instead of the standard API key method. The scope for this JWT would be just to use the Slicer and nothing more. This is a Beta feature and usage can be requested at [email protected]. If a JWT is used with the Slicer, currently direct API calls to the Slicer will not work.

To use the JWT, in the Slicer config file, the apikey parameter would be specified as:

apikey: token_MyJWT

where MyJWT would come from the Token Debugger.

These are the use cases where you may want to use a JWT with the Slicer:

  • Prevent general system access when just Slicer functionality is desired.
  • Allow a Slicer to be used for a certain window of time:
    • The JWT for the Slicer is created using the Token Debugger and has no expiration time.
    • The XAuth key is configured to not allow this token to be used after a certain time.
  • Use different JWTs for groups of Slicers to limit the damage in case a JWT is compromised.

To create a Scoped API Key for the Slicer:

  • Go to Settings tab in CMS
  • Click Scoped API Keys tab
  • Click + Key

  1. Enter a name for the Scoped API Key
  2. Enter a description for the Scoped API Key

  1. Click on Scopes tab
  2. Scroll down to Ingest

  1. Select Slicer - Operator under Ingest
  2. Scroll up to display Info, Scopes, and Advanced tabs at top of scroll area

  1. Click on Advanced tab
  2. Set a Valid Until date which keeps JWTs from being used past this time
  3. Click Create

To save the key information:

  1. Click on Download .env File to save the public and private encryption keys in cleartext
  2. After downloading, click the checkbox
  3. Click Close

To get the Slicer token:

  1. Click on Token Debugger

  1. Drag and drop or browse for the .env file created for the Slicer API key

  1. Click the checkbox for net to make the token never expire
  2. Note that the scope has video.services.ingest.slicer:ops permissions
  3. Copy the token here to the clipboard for pasting into a Slicer config file

To update the Slicer config file:

  1. Paste the token into the Slicer configuration file for the apikey setting preceded by _token__
  2. Restart the Slicer