OAuth2 clients

OAuth2 clients allow you to configure external services and applications to authenticate against Relativity in a secure manner. For example, a client application can present the user with the Relativity login page to get an access token to call Relativity APIs. The application can then call the APIs to perform tasks for customizing e-discovery workflows and automation.

You can programmatically interact with OAuth2 Clients using the IOAuth2ClientManager interface. You can also use the OAuth2 Client Manager REST service for cross-platform and browser-based applications.

This page contains the following information:

See these related pages:

OAuth2 Client fundamentals

Familiarize yourself with the Relativity OAuth2 Client user interface and review the information in the Relativity Documentation site. Note there is a strong correlation between the API operations and object properties and the user interface elements.

Use these guidelines when working with OAuth2 Clients:

  • To access the IOAuth2ClientManager interface, add the Relativity.Services.Interfaces.dll reference to your Visual Studio project. The file can be found in the Relativity SDK. For more information, see Set up your development environment.
  • The Relativity user accessing the API must have the permissions required for working with OAuth2 client objects.
  • Before creating a Relativity OAuth2 client, you must correctly identify the flow (grant type) required by the client application. The supported flows are defined by the OAuth2Flow enum and include:
    • Implicit (0)
    • Code (1)
    • ClientCredentials (2)
    • ResourceOwner (3)
  • OAuth2Client object properties include:
    • AccessTokenLifetimeInMinutes – the duration (in minutes) for which access tokens issued to the clients are valid. The recommended duration varies depending on the specified OAuth2 flow:
    • ContextUser – the user that will be assigned to the OAuth2 client for permissions and auditing. ContextUser property is required if ClientCredentials is selected as the OAuth2 flow, and can't be specified for other flows.
    • Description – the description for the OAuth2 client.
    • Enabled – indicates whether the client will be given access to Relativity. When a client is created, the value is automatically set to True,
    • Flow -the mechanism for acquiring an authentication token also know as OAuth2 grant type. The values are defined by the OAuth2Flow enum. This property is required when creating clients and cannot be updated.
    • Id – the unique identifier for the client. If you don't specify the value when creating the client (using the overloaded CreateAsync method), it is autogenerated by Relativity.
    • IsSystem – specifies whether the OAuth2 client is an internal Relativity application. This property is read-only.
    • Name – the descriptive name of the OAuth2 client. Required when creating clients. The name must be unique.
    • RedirectUris – the URLs that the user can be redirected back to after the request is authorized. Specify values for Implicit or Code Flow types.
    • Scopes – list of scopes this client is allowed to request. Currently the property can't be set. These are the default scopes for different OAuth2 flows:

      Scope / Flow

      Implicit

      Client Credentials

      Code

      Resource Owner

      id_token

       

      access_token

      refresh_token

       

    • Secret – the unique secret used by the client. The value is autogenerated by Relativity if you specify Client Credential, Resource Owner, or Code as the Flow type.
  • A typical programming workflow includes first creating an OAuth2 client object, and then specifying how long the access token granted to the client is valid.
  • Occasionally it may be necessary to regenerate the client secret for security purposes. The reset can take effect immediately or with a specified delay.
  • System OAuth2 clients can't be deleted.

Note: If you are developing your application with the IOAuth2ClientManager interface, download the Relativity.SecureTokenService.Services.Interfaces.dll file from the Resource Files tab and add it to your Visual Studio project.

Create an OAuth2 client

To create an OAuth2 client:

  1. Like with other Services API interfaces, begin by accessing the IOAuth2ClientManager interface through a client proxy to the Services API and instantiating a clientManager object. How you build the client proxy depends on how you plan to use it. If you plan to use it in a custom page, event handler, or agent, you can use API Helpers:
      Relativity.Services.Security.IOAuth2ClientManager clientManager = this.Helper.GetServicesManager().CreateProxy<Relativity.Services.Security.IOAuth2ClientManager>(ExecutionIdentity.System);

    Otherwise, you can instantiate the clientManager object using the ServiceFactory class:

    Uri restUri = new Uri("http://mycompany.com/Relativity.REST/api");
    UsernamePasswordCredentials credentials = new UsernamePasswordCredentials("jsmith@mycompany.com", "YourPasswordGoesHere2016!");
    
    ServiceFactorySettings settings = new ServiceFactorySettings(restUri, credentials);
    ServiceFactory serviceFactory = new ServiceFactory(settings);
    
    using (IOAuth2ClientManager clientManager = serviceFactory.CreateProxy<IOAuth2ClientManager>())
    { ...
    

    For more information about creating proxies, see Connect to the Services API.

  2. Call the CreateAsync() method of the IOAuth2ClientManager interface and pass it the name, the flow, and the list of redirect URIs:
      OAuth2Client client = await clientManager.CreateAsync("eDiscover123", OAuth2Flow.Implicit, new List<Uri>() { new Uri("http://ediscover123.com/start") }, null);

    If you must create a client with a specified Client ID, use the overloaded CreateAsync method that takes in an OAuth2Client object:

    string newId = Constants.MY_APP_CLIENT_ID;
    OAuth2Client client = await clientManager.CreateAsync(new OAuth2Client {
    	Id = newId,
    	Name = "eDiscover123",
    	Flow = OAuth2Flow.Implicit,
    	RedirectUris = new List&lt;Uri&gt; { new Uri("http://ediscover123.com/start") },
    	AccessTokenLifetimeInMinutes = 10
    });
      Notes:
    • You can’t create a Client with an ID that already exists.
    • Setting the Secret property of the OAuth2Client is currently unsupported.

    You have created the OAuth2 client and can now update it, for example, to make it active and set the access token lifetime.

Update an OAuth2 client

To update an OAuth2 client after you create it:

  1. Update the properties on the OAuth2Client object. In this example, we make the client active and set the access token lifetime to 10 minutes:
    client.AccessTokenLifetimeInMinutes = 10;
    client.Enabled = true;
  2. Call the SaveAsync() method of the IOAuth2ClientManager interface and pass it the OAuth2Client object with updated property values:
      await clientManager.SaveAsync(client);

Regenerate a client secret

To regenerated a client secret, call the RegenerateSecretAsync() method of the IOAuth2ClientManager interface and pass the generated ID of the OAuth2 client:

  string newSecret = await clientManager.RegenerateSecretAsync(client.Id);

To regenerated a client secret with a delay:

  • Instantiate the clientManager object with bearer token credentials for the client you want to regenerate.
  • Call the RollMySecretAsync() and pass the old secret and a TimeSpan object specifying how long you want the old secret to remain valid.
Uri tokenEndpoint = new Uri("http://mycompany.com/Relativity/identity/connect/token");
// Using the IdentityModel library [ https://github.com/IdentityModel ]
var client = new TokenClient(
    tokenEndpoint,
    "client_id",
    "secret");

var response = await client.RequestClientCredentialsAsync("scope");
var token = response.AccessToken;

Uri restUri = new Uri("http://mycompany.com/Relativity.REST/api");
BearerTokenCredentials credentials = new BearerTokenCredentials(token);

ServiceFactorySettings settings = new ServiceFactorySettings(restUri, credentials);
ServiceFactory serviceFactory = new ServiceFactory(settings);

using (IOAuth2ClientManager clientSecretManager = serviceFactory.CreateProxy<IOAuth2ClientManager>())
{
    string newSecret = await clientSecretManager.RollMySecretAsync(client.Secret, Timespan.FromMinutes(5));
}

Read all OAuth2 clients

To read all OAuth2 clients defined for a Relativity instance, call the ReadAllAsync() method of the IOAuth2ClientManager interface:

  List<OAuth2Client> clients = await clientManager.ReadAllAsync();

Read an OAuth2 client

To read a single OAuth2 client, call the ReadAsync() method of the IOAuth2ClientManager interface and pass the generated ID of the OAuth2 client:

  OAuth2Client client = await clientManager.ReadAsync(client.Id);

Delete an OAuth2 client

To delete an OAuth2 client, call the ReadAsync() method of the IOAuth2ClientManager interface and pass the generated ID of the OAuth2 client:

  await clientManager.DeleteAsync(client.Id);

Example

This example demonstrates how to create an OAuth2 Client that uses Implicit flow to get the access token, update it so that it is enabled and has a defined token lifetime, and then delete it:

using System.Collections.Generic;
using System.Threading.Tasks;
using Relativity.Services.Security;
using Relativity.Services.Security.Models;
using Relativity.Services.ServiceProxy;

namespace OAuth2ClientApiSample
{
    class Program
    {
        static void Main(string[] args)
        {
            RunSample().Wait();
        }

        public static async Task RunSample()
        {
            Uri restUri = new Uri("http://mycompany.com/Relativity.REST/api");
            UsernamePasswordCredentials credentials = new UsernamePasswordCredentials("jsmith@mycompany.com", "YourPasswordGoesHere2016!");

            ServiceFactorySettings settings = new ServiceFactorySettings(restUri, credentials);
            ServiceFactory serviceFactory = new ServiceFactory(settings);

            using (IOAuth2ClientManager clientManager = serviceFactory.CreateProxy<IOAuth2ClientManager>())
            {
                //Register a new client
                OAuth2Client client = await clientManager.CreateAsync("Test Implicit Client2", OAuth2Flow.Implicit, new List<Uri>() { new Uri("http://somesite.com") });

                client.AccessTokenLifetimeInMinutes = 10;
                client.Enabled = true;

                //Update
                await clientManager.SaveAsync(client);

                //Read
                client = await clientManager.ReadAsync(client.Id);

                //Delete
                await clientManager.DeleteAsync(client.Id);
            }
        }
    }
}

OAuth2 Client Manager REST service

The OAuth2 Client Manager service allows you to interact with OAuth2 Clients from browser-based and cross-platform applications. The service provides the same set of operations as the IOAuth2ClientManager .NET interface:

Create an OAuth2 client with REST

To create an OAuth2 client from a RESTful application, send a POST request to this OAuth2 Client Manager service URL:

  <host>/Relativity.REST/api/Relativity.Services.Security.ISecurityModule/OAuth2 Client Manager/CreateAsync

The request payload must include valid JSON representations of an OAuth2 client object:

{
    "name": "eReview123",
    "flow": "Code",
    "redirectUris": ["https://eReview123.com/start"],
    "contextUser": null
}

This is an example of the payload for creating a client with a specified ID:

{
    "newClient": {
        "id": "3c0b75dc-e10d-4047-87f3-f8b7a0a0e06c",
        "name": "eReview1234",
        "flow": "Implicit",
        "redirectUris": [
        "https://eReview123.com/start"
        ],
        "accessTokenLifetimeInMinutes": 10
    }
}

The response returns the created OAuth2 client object:

{
  "AccessTokenLifetimeInMinutes": 480,
  "Name": "eReview123",
  "Enabled": true,
  "Flow": "Code",
  "Id": "da1fa8353de89bc2cbd9f2821a",
  "IsSystem": false,
  "RedirectUris": [
    "https://eReview123.com/start"
  ],
  "Secret": "5e8de4a6521ba4afc8f43cc37a62395e4d62e57a",
  "Scopes": []
}

Update an OAuth2 client with REST

To update an OAuth2 client, send a POST request to this OAuth2 Client Manager service URL:

  <host>/Relativity.REST/api/Relativity.Services.Security.ISecurityModule/OAuth2 Client Manager/SaveAsync

The request payload must include valid JSON representations of the OAuth2 client object with updated values:

{
  "client": {
    "AccessTokenLifetimeInMinutes": 14400,
    "Name": "eReview123",
    "Enabled": false,
    "Flow": "Code",
    "Id": "64671eda70e4290eee5d1ded8a",
    "RedirectUris": [
      "https://eReview123.com/start",
      "http://eReview123.com/start"
    ]
  }
}

The response does not contain any data. Success or failure is indicated by the HTTP status code. For more information, see HTTP status codes.

Regenerate a client secret with REST

To regenerate an OAuth2 client secret, send a POST request to this OAuth2 Client Manager service URL:

  <host>/Relativity.REST/api/Relativity.Services.Security.ISecurityModule/OAuth2 Client Manager/RegenerateSecretAsync

The request payload must include the generated client ID:

{
  "Id": "da1fa8353de89bc2cbd9f2821a"
}

The response returns the string value of the client's new secret:

  ccce232bccd58a467554c718e8638058ade3096b

To regenerate a secret with a delay, authenticate using a bearer token generated for the OAuth2 client, and send a POST request to this OAuth2 Client Manager service URL:

  <host>/Relativity.REST/api/Relativity.Services.Security.ISecurityModule/OAuth2 Client Manager/RollMySecretAsync

The request payload must include the old client secret and the timespan:

{
    "secret": "ccce232bccd58a467554c718e8638058ade3096b",
    "timespan": "00:00:01:00",
}

The response returns the string value of the client's new secret:

  5e8de4a6521ba4afc8f43cc37a62395e4d62e57a

Read an OAuth2 client with REST

To read a single OAuth2 client, send a POST request to this OAuth2 Client Manager service URL:

  <host>/Relativity.REST/api/Relativity.Services.Security.ISecurityModule/OAuth2 Client Manager/ReadAsync

The request payload must include the generated client ID (Relativity-generated value):

{
  "Id": "da1fa8353de89bc2cbd9f2821a"
}

The response returns the OAuth2 client object:

{
  "AccessTokenLifetimeInMinutes": 480,
  "Name": "eReview123",
  "Enabled": true,
  "Flow": "Code",
  "Id": "da1fa8353de89bc2cbd9f2821a",
  "IsSystem": false,
  "RedirectUris": [
    "https://eReview123.com/start"
  ],
  "Secret": "5e8de4a6521ba4afc8f43cc37a62395e4d62e57a",
  "Scopes": []
}

Read all OAuth2 clients with REST

To read all OAuth2 clients in a Relativity instance, send a POST request to this OAuth2 Client Manager service URL:

  <host>/Relativity.REST/api/Relativity.Services.Security.ISecurityModule/OAuth2 Client Manager/ReadAllAsync

The response returns a collection of OAuth2 client objects:

[
  {
    "AccessTokenLifetimeInMinutes": 144000,
    "Name": "TokenizerRescOwner",
    "Enabled": true,
    "Flow": "ResourceOwner",
    "Id": "c6614487-1a13-4b1c-847b-1e2e4ed934ee",
    "IsSystem": true,
    "RedirectUris": [],
    "Secret": "1652b752-354d-4568-b1e4-6b037c6a70c3",
    "Scopes": []
  },
  {
    "AccessTokenLifetimeInMinutes": 144000,
    "Name": "Tokenizer",
    "Enabled": true,
    "Flow": "ClientCredentials",
    "Id": "a232184f-ab51-4bb4-8bc1-36356fcae28f",
    "IsSystem": true,
    "RedirectUris": [],
    "Secret": "2f61baf6-2242-436b-b4b8-afd769bdf95e",
    "Scopes": []
  },
  {
    "AccessTokenLifetimeInMinutes": 144000,
    "Name": "Relativity",
    "Enabled": true,
    "Flow": "Code",
    "Id": "bd10a60d-b8ec-4928-84ee-6fc4f30d9612",
    "IsSystem": true,
    "RedirectUris": [
      "http://local.dynamic.com/"
    ],
    "Secret": "b9d0a91b-887f-4b97-bd60-0cde37da3768",
    "Scopes": []
  },
  {
    "AccessTokenLifetimeInMinutes": 512640,
    "Name": "System",
    "Enabled": true,
    "Flow": "ClientCredentials",
    "Id": "aea8cf48-37d0-40bd-a2ce-c40e8654d0c5",
    "IsSystem": true,
    "RedirectUris": [],
    "Secret": "d97b3813-ff55-49a2-9b89-7e07082ebfb1",
    "Scopes": []
  },
  {
    "AccessTokenLifetimeInMinutes": 14400,
    "Name": "eDiscover123",
    "Enabled": true,
    "Flow": "Code",
    "Id": "0ff0b4c7ec28a538c8dcb8534b",
    "IsSystem": false,
    "RedirectUris": [
      "https://ediscover123.com/start"
    ],
    "Secret": "1a004dacc4a9422d2974f9d3f0dcb226e6e6ba5d",
    "Scopes": []
  },
  {
    "AccessTokenLifetimeInMinutes": 10,
    "Name": "ReviewStatsCheck",
    "Enabled": true,
    "Flow": "Implicit",
    "Id": "e170f9d811dfc97b3d1ab9f716",
    "IsSystem": false,
    "RedirectUris": [
      "http://somesite.com/"
    ],
    "Secret": "",
    "Scopes": []
  },
  {
    "AccessTokenLifetimeInMinutes": 480,
    "Name": "Test Implicit Client2",
    "Enabled": true,
    "Flow": "Implicit",
    "Id": "006892cfb54b84306f32ef0e8e",
    "IsSystem": false,
    "RedirectUris": [
      "http://somesite.com/"
    ],
    "Secret": "",
    "Scopes": []
  },
  {
    "AccessTokenLifetimeInMinutes": 14400,
    "Name": "eReview123",
    "Enabled": false,
    "Flow": "Code",
    "Id": "64671eda70e4290eee5d1ded8a",
    "IsSystem": false,
    "RedirectUris": [
      "https://ereview123.com/start",
      "http://ereview123.com/start"
    ],
    "Secret": "ccce232bccd58a467554c718e8638058ade3096b",
    "Scopes": []
  }
]

Delete an OAuth2 client with REST

To delete an OAuth2 client from a RESTful application, send a POST request to this OAuth2 Client Manager service URL:

  <host>/Relativity.REST/api/Relativity.Services.Security.ISecurityModule/OAuth2 Client Manager/DeleteAsync

The request payload must include the client ID (Relativity-generated value):

{
  "Id": "da1fa8353de89bc2cbd9f2821a"
}

The response does not contain any data. Success or failure is indicated by the HTTP status code. For more information, see HTTP status codes.

Authenticate with OAuth2 and client credentials

The following code sample illustrates how to authenticate with OAuth2 and client credentials.

using kCura.Relativity.Client;
using Relativity.OAuth2Client.IdentityModel.Client;
using Relativity.OAuth2Client.IdentityModel.Interfaces;
using Relativity.Services.ServiceProxy;
using BearerTokenCredentials = Relativity.Services.ServiceProxy.BearerTokenCredentials;

namespace BearerOoAuth2Ex
{
    class ConnectionManager
    {
        public static ITokenResponse token = null;

        public IRESTClient TestoAuth2()
        {
            KeplerApiConfig keplerApiConfig = new KeplerApiConfig
            { // Set the values for your environment here.

                RestUri = "https://<myserver.mycompany.corp>/Relativity.Rest/API",
                //Create an OAuth2 client of type client credentials. Use the values that it provides here.
                ClientId = "<MyCLientID>",
                ClientSecret = "<YourClientSecret>",
                IdentityServerTokenUrl = "https://<myserver.mycompany.corp>/Relativity/Identity/connect/token"
            };

            // Set up a connection with bearer token authentication.
            var serviceFactory = GetServiceFactory(keplerApiConfig);
            IRESTClient proxy = serviceFactory.CreateProxy<IRESTClient>();
            return proxy;
        }

        public static ServiceFactory GetServiceFactory(KeplerApiConfig config)
        {
            Uri hostUri = new Uri(config.RestUri);

            using (TokenClient clientToken = new TokenClient(config.IdentityServerTokenUrl, config.ClientId, config.ClientSecret))
            {
                token = clientToken.RequestClientCredentialsAsync("SystemUserInfo").ConfigureAwait(false).GetAwaiter().GetResult();
                if (token.Exception != null)
                {
                    throw token.Exception;
                }
            }
            BearerTokenCredentials bearerToken = new BearerTokenCredentials(token.AccessToken);
            ServiceFactorySettings settings = new ServiceFactorySettings(hostUri, bearerToken);
            return new ServiceFactory(settings);
        }

        public class KeplerApiConfig
        {
            public string RestUri { get; set; }
            public string ClientId { get; set; }
            public string ClientSecret { get; set; }
            public string IdentityServerTokenUrl { get; set; }
        }
    }
}