Networked Media Open Specifications

Controller to Authorization Server Interactions

←Node to Registry Interactions (IS-04) · Index↑ · Controller to Registry (IS-04) and Node Interactions (IS-05, IS-08)→

Overview

This section details the interactions between an NMOS Controller and the Authorization Server. These include:

Controller to Authorization Server Interactions

The sequence diagram above gives an overview of these interactions which are described in more detail below.

Authorization Server Discovery

In order to interact with the Authorization Server, you need to know where it is. IS-10 specifies that the Authorization Server advertise itself using unicast DNS-SD to advertise itself to the Controller.

Once the Controller knows the whereabouts of the Authorization Server it can then fetch the Authorization Server Metadata to obtain supported features and endpoints.

Example request to get server metadata:

GET /.well-known/oauth-authorization-server HTTP/1.1
Host: authorization-server.example.com

Example server metadata HTTP response:

HTTP/1.1 200 OK
Content-Type: application/json
{
  "authorization_endpoint": "https://authorization-server.example.com/authorize",
  "code_challenge_methods_supported": [
    "plain",
    "S256"
  ],
  "grant_types_supported": [
    "authorization_code",
    "implicit",
    "refresh_token",
    "password",
    "client_credentials"
  ],
  "issuer": "https://authorization-server.example.com",
  "jwks_uri": "https://authorization-server.example.com/jwks",
  "registration_endpoint": "https://authorization-server.example.com/register",
  "request_object_signing_alg_values_supported": [
    "PS384",
    "ES384",
    "RS384",
    "HS256",
    "HS512",
    "ES256",
    "RS256",
    "HS384",
    "ES512",
    "PS256",
    "PS512",
    "RS512",
    "none"
  ],
  "response_types_supported": [
    "code",
    "none",
    "token",
    "code token"
  ],
  "scopes_supported": [
    "channelmapping",
    "connection",
    "events",
    "node",
    "query",
    "registration"
  ],
  "token_endpoint": "https://authorization-server.example.com/token",
  "token_endpoint_auth_methods_supported": [
    "private_key_jwt",
    "client_secret_basic",
    "client_secret_post",
    "tls_client_auth",
    "client_secret_jwt"
  ],
  "token_endpoint_auth_signing_alg_values_supported": [
    "PS384",
    "ES384",
    "RS384",
    "HS256",
    "HS512",
    "ES256",
    "RS256",
    "HS384",
    "ES512",
    "PS256",
    "PS512",
    "RS512"
  ]
}

Client Registration

The NMOS Controller first needs to register with the Authorization Server. This is usually a one-time operation that a Controller would typically perform when first activated on the network.

The registration is done via a dynamic client registration with the Authorization Server. The registration includes the expected grant type, which is set to authorization code grant.

Depending on how the Authorization Server has been configured, it is likely that the Client Registration will need to be authenticated using an Initial Access Token. This token will be generated by the Authorization Server, and provided to the NMOS Controller by some proprietary method.

When registering an NMOS Controller with more than one Authorization Server, the registration of unique redirect_uris for each Authorization Server can help in avoiding Authorization Server Mix-Up attacks on your controller, whether it be a native application (RFC 8252, Section 8.10) or browser-based application (OAuth 2.0 for Browser-Based Apps, Section 9.5).

Example public client registration request including an Initial Access Token (this follows the Authorization: Bearer in the HTTP header):

NOTE: The parameters passed as part of the dynamic client registration of NMOS Controllers are different to those passed when registering an NMOS Node.

POST /register HTTP/1.1
Host: authorization-server.example.com
Content-Type: application/json
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCIg...
{
  "client_name": "My Example Controller",
  "grant_types": [
    "authorization_code",
    "refresh_token"
  ],
  "redirect_uris": [
    "https://controller.example.com/auth/callback"
  ],
  "response_types": [
    "code"
  ],
  "scope": "channelmapping connection events node query",
  "token_endpoint_auth_method": "none"
}

Example response:

HTTP/1.1 201 Created
Content-Type: application/json
{
  "client_id": "40baf617-1744-4c24-9baf-22351bec1a73",
  "client_name": "My Example Controller",
  "client_id_issued_at": 1611940142,
  "grant_types": [
    "authorization_code",
    "refresh_token"
  ],
  "redirect_uris": [
    "https://controller.example.com/auth/callback"
  ],
  "response_types": [
    "code"
  ],
  "token_endpoint_auth_method": "none"
}

Authorization Code Flow

NMOS Controllers can be implemented as either OAuth 2.0 public clients or confidential clients.

The IS-10 specification recommends making use of a Proof Key for Code Exchange (PKCE) (defined in OAuth 2.0 RFC 7636) as part of the Authorization Code Flow.

Example request to start authorization code flow:

GET /authorize
?client_id=30baf617-1744-4c24-9baf-22351bec1a73
&redirect_uri=https%3A%2F%2controller.example.com/auth/callback
&response_type=code
&code_challenge=HbYjeCHvDfKpyYacEHKLdffF0geuyu3A-b4ir7ZG8-E
&code_challenge_method=S256
&state=ricgtUUXODcOzifiJDnOw25rZ8wTZCxU
&scope=channelmapping%20connection%20events%20node%20query
HTTP/1.1
Host: authorization-server.example.com

Example of authorization code ‘returned’ via the redirect URI (in this example, passed in the code parameter):

HTTP/1.1 302 Found
Location: https://controller.example.com/auth/callback
?state=ricgtUUXODcOzifiJDnOw25rZ8wTZCxU
&code=2b7488e0-0682-42bb-893c-9d09e60bf8...

Example request to exchange authorization code for bearer token (in this request, the code is the authorization code):

POST /token HTTP/1.1
Host: authorization-server.example.com
Content-Type: application/x-www-form-urlencoded
client_id=30baf617-1744-4c24-9baf-22351bec1a73
&redirect_uri=https://controller.example.com/auth/callback
&code=2b7488e0-0682-42bb-893c-9d09e60bf8...
&grant_type=authorization_code
&code_verifier=ricgtUUXODcOzifiJDnOw25rZ8wTZCxUxf...
&scope=channelmapping connection events node query

Example token response:

HTTP/1.1 200 OK
Content-Type: application/json
{
  "access_token": "eyJhbGciOiJSUzUxMiIsInR5cCIgOiAiSl...",
  "expires_in": 180,
  "refresh_expires_in": 1800,
  "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCIgOiAiSldUIiwia...",
  "scope": "channelmapping connection events node query",
  "token_type": "bearer"
}

Refreshing Bearer Tokens

The Bearer Token has a limited life specified by the value of the expires_in parameter in seconds. The Controller needs to refresh the token before it exceeds its half life (for example if the token lifetime is 30 seconds, then refresh it at least 15 seconds before token expiry).

Because refresh tokens can have a long lifetime, it is important that they are stored securely to prevent them from being leaked.

Example request to refresh bearer token:

POST /token HTTP/1.1
Host: authorization-server.example.com
Content-Type: application/x-www-form-urlencoded
client_id=30baf617-1744-4c24-9baf-22351bec1a73
&grant_type=refresh_token
&refresh_token=eyJhbGciOiJIUzI1NiIsInR5cCIgOiAiSldUIiwia...

In this request the refresh_token was previously obtained from the bearer token.

Example token response:

HTTP/1.1 200 OK
Content-Type: application/json
{
  "access_token": "eyJhbGciOiJSUzUxMiIsInR5cCIgOiAiSl...",
  "expires_in": 180,
  "refresh_expires_in": 1800,
  "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCIgOiAiSldUIiwia...",
  "scope": "channelmapping connection events node query",
  "token_type": "bearer"
}

Note that when a Controller is unable to contact an Authorization Server, it needs to try to contact another Authorization Server from the discovered list until this either succeeds or the list is exhausted.

←Node to Registry Interactions (IS-04) · Index↑ · Controller to Registry (IS-04) and Node Interactions (IS-05, IS-08)→