Authentication to an Activate API using OAuth through Azure
Setup Activate application in Azure
This document assumes the Activate application in Azure has already been setup, if not refer to Activate Azure App Quick Start Guide
Register Client Application
Login to your organisation’s Azure portal and select Manage Entra ID
- Click App registrations
- Click New Registration, enter the following values
- Name = “ACME Test Client”, enter your client name, we will use “ACME Test Client” as an example in this document.
- Supported account types = “Accounts in this organizational directory only (<your domain> only - Single tenant)”
- Redirect URI can be left blank
- Click Register button
- Copy the Application (client) ID for later
Create Secret for Client Application
The client will use this to acquire a token which it will send to the Activate API for authentication.
- Navigate back to App Registrations and select the previously created ACME Test Client application.
- Select Certificates & secrets from the left
- Click New client secret
- Enter values
- Description = Description of the secret
- Select an appropriate Expires value
- Click Add
- Copy the value of the new secret, this will be used by the Client application to obtain an access token. This should be treated like a password and only shared with appropriate parties.
Configure App Role
- In Azure Portal access the Enterprise Applications list
- Select the Activate application (name may differ in your environment)
- Click the Properties menu option on the left
- If Assignment required? Option is set to Yes proceed to step #5, if set to No then proceed to API Permissions section.
- Navigate back to App registrations and the Activate application.
- Select the App roles menu option
- Click Create app role
- Enter values
- Display Name = “Activate Custom API Access”
- Allowed Member Types = “Applications”
- Value = “Activate.Custom.API.Access”
- Description = “Role to allow access to Activate Custom APIs”
- Do you want to enable this app role? = Checked
- Click Apply
API Permissions
- Navigate to App Registrations
- Select your Client application. This is the app that will be connecting to the API.
- Select menu option API Permissions
- Assign Activate Custom API Access role, only required if Assignment required is turned on as per previous section
- Click Add a permission
- Click tab My APIs
- Click Activate application. If the application is not available in the My APIs tab, try the APIs my organization uses
- Check Activate.Custom.API.Access from the Activate permissions list
- Click Add permissions button
- Add User.Read permission to allow application to read its profile
- Click Add a permission
- Select Microsoft Graph
- Select Delegated permissions
- Enter “User.Read” into the search
- Drop down User
- Check User.Read, Sign in and read user profile.
- Click Add permissions button
- Click Grant admin consent for <domain>
- Confirm admin consent
Other configuration
In order to get the correct token content, the version of the token must be explicitly configured in the application manifest.
- Navigate to the Activate app registration
- Click the Manifest option on the left
- Change accessTokenAcceptedVersion to “2” if it isn’t set to that already.
- Click Save
Setup Activate API
- Create a UserReference parameter named OAuth::<application ID of Client application in Azure> on the Activate Custom API. This authorises the application to access the API in Activate. Point the user to an Activate API User role member or user with Execute/Read security rights on the API resource.
- Set Authentication = OAuth
Client Example
This is an Activate script which can be used to test the connection to the Activate API, acting as the client.
//@import System.Net.Http
//@import Microsoft.Identity.Client
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Threading.Tasks;
using Innovation.Activate;
using Microsoft.Identity.Client;
class Script : ScriptBase
{
string URL = "<full path to API here>";
string appSecret = "<test client secret here>";
string tenantName = "<tenant name here>";
string appID = "<client app ID here>";
ConfidentialClientApplication application;
public void main()
{
// Get Activate application, this forms the scope of the access token request
string scope = $"api://{Evaluator.GetString("=//Resources/ActiveDirectory/External Directories/Azure/ApplicationID")}/.default";
HttpClient http = GetHttpClient(new List<string> { scope });
Trace.WriteLine("Logged in");
HttpRequestMessage m = new HttpRequestMessage(HttpMethod.Get, URL);
HttpResponseMessage r = http.SendAsync(m).Result;
Trace.WriteLine(string.Format("{0}: {1}", r.StatusCode.ToString(), r.ReasonPhrase));
Trace.WriteLine(string.Format("[{0}]", r.Content.ReadAsStringAsync().Result));
}
// Get an authenticated Microsoft Graph Service client.
public HttpClient GetHttpClient(List<string> scopes)
{
HttpClient httpClient = new HttpClient();
string accessToken = Task.Run<string>(() =>
{
return GetAppAccessTokenAsync(scopes);
}).Result;
// Append the access token to the request.
httpClient.DefaultRequestHeaders.Add(
"Authorization",
string.Format("Bearer {0}", accessToken)
);
return httpClient;
}
// Get an access token. First tries to get the token from the token cache.
public async Task<string> GetAppAccessTokenAsync(List<string> scopes)
{
// wrong token version is being returned
string authority = string.Format(
@"https://login.microsoftonline.com/{0}/oauth/V2.0/authorize",
tenantName
);
var application =
ConfidentialClientApplicationBuilder
.Create(appID)
.WithAuthority(AzureCloudInstance.AzurePublic, tenantName)
.WithClientSecret(appSecret)
.Build();
AuthenticationResult result =
await application.AcquireTokenForClient(scopes).ExecuteAsync();
return result.AccessToken;
}
}
Troubleshooting
HTTP Code | Possible Cause |
|---|---|
403 - Forbidden | Execute API rights to user not configured |
401 - Unauthorized | Token has not been validated, check TenantID is configured on //Resources/External Directories/Azure, this is used to determine the issuer. |
500 - Internal Server Error | OAuth::<apiKey> not configured |