Starting with release 3.6 you can develop your own OAuth providers for Neuron ESB. This article discusses developing custom OAuth providers.
OAuth 2.0 Grant Types
When developing custom OAuth providers, one of the first steps is to determine which grant type(s) you want to support. There are five grants for obtaining an access token:
- Authorization Code Grant
- Implicit Grant
- Client Credentials Grant
- Resource Owner Credentials Grant
- Refresh Token Grant
Each of these except for the Implicit Grant type can be used by Neuron ESB. The Implicit Grant type is intended to be used by user-agent-based clients, like single page web apps that are unable to keep a client secret. Below are descriptions of the other four grants and how Neuron ESB utilizes them.
Authorization Code Grant
The Authorization Code Grant is one of the most commonly used OAuth grant types. It requires user intervention during the setup process, but can still be used by Neuron ESB for connecting to applications that require OAuth for providing access. There are three steps to using the authorization code grant with Neuron ESB:
- Application Registration – The first step in using this grant type requires you to register an application with the OAuth service you want to use (i.e. Azure Active Directory). When you register the application you will be assigned a client Id and client secret by the OAuth service.
- Register the OAuth Provider in Neuron ESB – In Neuron ESB Explorer you will create a new OAuth provider registration, selecting the appropriate OAuth provider and entering the appropriate properties, including the client Id and client secret obtained in step 1.
- Retrieve an Access Token – After entering all the information for registering an OAuth provider in step 2, click the “Test” button in Neuron ESB Explorer. When using the Authorization Code Grant, this will open a mini browser window and redirect you to the OAuth services login application. You will login using your credentials for that service and grant access to that application. After completing this step an access token is returned to Neuron ESB Explorer. That access token is used when making calls to service endpoints that are configured to use this OAuth provider.
Some OAuth services that support this grant type will return access tokens that never expire. Most OAuth providers that return access tokens that expire will also return a refresh token that can be used to retrieve a new access token. If a refresh token is returned in step 3, Neuron will also save that refresh token and automatically use it when the original access token expires. There may be OAuth providers that return access tokens that expire and do not return refresh tokens. We recommend against using these OAuth providers unless it’s absolutely necessary. When the original access token expires, the only way to get a new one will be for a user to manually use the “Test” button on the OAuth provider details UI in Neuron ESB Explorer.
Client Credentials Grant
The Client Credentials Grant is the simplest grant to use. It’s the best suited grant for machine-to-machine authentication where a specific user’s permission to access data is not required. There are just two steps to using the Client Credentials Grant with Neuron ESB:
- Application Registration – The first step in using this grant type requires you to register an application with the OAuth service you want to use (i.e. Azure Active Directory). When you register the application you will be assigned a client Id and client secret by the OAuth service.
- Register the OAuth Provider in Neuron ESB – In Neuron ESB Explorer you will create a new OAuth provider registration, selecting the appropriate OAuth provider and entering the appropriate properties, including the client Id and client secret obtained in step 1.
Unlike the authorization code grant, you do not need to log-into the OAuth service and grant access the application. You can still click the “Test” button and an access token will be retrieved and stored with the OAuth provider registration. When calling a service endpoint that is configured with this OAuth provider, Neuron ESB will initially attempt to use the access token that was retrieved when clicking the “Test” button. If you did not click the “Test” button or the access token is expired, Neuron ESB will automatically request a new access token using the client Id and client secret retrieved in step 1 above. The Client Credentials Grant does not return refresh tokens.
Resource Owner Credentials Grant
The Resource Owner Credentials Grant is a good option to use between trusted parties. This grant type requires a username and password to be sent with the request for an access token. These credentials can be any user that has access to the resource. It is recommended that a user account be created specifically for Neuron ESB when this grant type is used. The steps for using the Resource Owner Credentials Grant are similar to those for using the Client Credentials Grant:
- Application Registration – The first step in using this grant type requires you to register an application with the OAuth service you want to use (i.e. Azure Active Directory). When you register the application you will be assigned a client Id and client secret by the OAuth service.
- Register the OAuth Provider in Neuron ESB – In Neuron ESB Explorer you will create a new OAuth provider registration, selecting the appropriate OAuth provider and entering the username and password, along with any additional properties such as the client Id and client secret obtained in step 1.
Unlike the authorization code grant, you do not need to log-into the OAuth service and grant access the application. You can still click the “Test” button and an access token will be retrieved and stored with the OAuth provider registration. When calling a service endpoint that is configured with this OAuth provider, Neuron ESB will initially attempt to use the access token that was retrieved when clicking the “Test” button. If you did not click the “Test” button or the access token is expired, Neuron ESB will automatically request a new access token using the client Id and client secret retrieved in step 1 above. The Resource Owner Credentials Grant does return refresh tokens. When the access token expires, Neuron ESB will use the refresh token to obtain a new access token.
Refresh Token Grant
The refresh token grant is used in conjunction with other grants and allows you to request a new access token when the previous access token expires. Not all grants provide refresh tokens. The Authorization Code Grant and the Resource Owner Credentials Grant provide them. The Client Credentials Grant does not. When using either the Authorization Code Grant or the Resource Owner Grant, when an access token is retrieved a refresh token is returned with it. Neuron ESB saves the refresh token and uses it to request a new access token when the current one expires.
There are no setup steps required to use refresh tokens. Neuron ESB automatically utilizes them depending on the grant type used by the OAuth provider.
Developing Custom OAuth Providers
To develop your own custom OAuth provider, you will have to implement either two or three classes, depending on which OAuth grant type you’re using:
- A Provider class which inherits from Neuron.Esb.OAuth.OAuthProvider
- An OAuth Client class, which inherits from either Nemiro.OAuth.OAuth2Client (OAuth 2.0) or Nemiro.OAuth.OAuthClient (OAuth 1.0)
- An optional Login class, which inherits from Nemiro.OAuth.LoginForms.Login. This is only needed for the Authorization Code grant type.
These are the steps for creating your own OAuth provider:
- Determine which grant type you want to use with your OAuth provider.
- Determine provider-specific requirements for the grant type that you will be using
- Build the OAuth Provider solution
Determine which grant type to use
Most OAuth providers only support one or two of the available grant types, so you will need to do some research to see what options you have. If your OAuth provider supports the Client Credentials grant type, you should use that one. This grant type is the easiest to use and requires the least amount of maintenance once implemented. The other two grant types – Authorization Code and Resource Owner Credentials – may require ongoing maintenance as tokens expire or passwords change. Depending on your OAuth provider you may not have a choice in which grant type to use.
Determine provider-specific requirements
The OAuth specification provides a baseline that OAuth providers need to support. Some OAuth provides, like Azure Active Directory, have additional requirements on top of the specification. Azure Active directory requires a “Resource” parameter be sent with token requests. This Resource parameter defines which Microsoft cloud-based application you want an access token for (i.e. Dynamics CRM or SharePoint Online).
There are a number of samples available that demonstrate how to implement provider-specific requirements in your custom OAuth provider.
Build the OAuth Provider solution
There are several custom OAuth provider samples included with the Neuron ESB installation. Three of these samples are generic implementations of the three grant types supported by Neuron. We recommend you start with the sample that matches the grant type you want to implement. It’s likely that the generic sample is sufficient for your requirements. However, if your OAuth provider has custom requirements, i.e. Azure Active Directory, then you will have to add those requirement to the generic sample. For your reference, there are also two sample OAuth providers that demonstrate how to implement the Authorization Code and Client Credentials grant types for Azure Active Directory.
The rest of this document provides the details on how to build an OAuth provider from scratch.
Create a new Visual Studio solution
You can use Visual Studio 2013 and later to build the OAuth Provider. The main Visual Studio requirement is that you have the Microsoft .NET Framework 4.7.1 Targeting Pack installed.
Open Visual Studio and create a new Class Library (.NET Framework) project:
Configure project settings
Open the project settings and set the Target Framework to .NET Framework 4.7.1. If you do not see this option, then most likely the correct .NET Framework Targeting Pack is not installed. Optionally set the Assembly Name and Default Namespace:
Change the name of the class file
Change the default class file name from Class1.cs to the name of your provider. In the sample below I chose SampleOAuthProvider:
Add Nemiro Libraries to the solution
Neuron ESB utilizes the Nemiro.OAuth and Nemiro.OAuth.LoginForms libraries in its implementation of OAuth providers. You will also need to reference these libraries when creating your own OAuth providers. These libraries are shipped with Neuron ESB, so you can reference these libraries either by direct reference to the files in the Neuron installation folder or by adding them via NuGet in Visual Studio.
If you reference the libraries directly, add references to these files:
- <Neuron Install Location>\<Instance>\Nemiro.OAuth.dll
- <Neuron Install Location>\<Instance>\Nemiro.OAuth.LoginForms.dll
If you add them to your solution via NuGet, add these libraries:
- Nemiro.OAuth (version 1.13.0)
- Nemiro.OAuth.LoginForms (version (1.7.0)
The versions listed above are the versions shipped with Neuron ESB 3.6. You may want to check the versions of these files in the Neuron installation directory before adding the libraries with NuGet.
Add Reference to Neuron.Esb.dll
Add a reference to the Neuron.Esb assembly found here:
- <Neuron Install Location>\<Instance>\Neuron.Esb.dll
Implement the OAuth2Client or OAuthClient class
This class inherits Nemiro.OAuth.OAuth2Client or Nemiro.OAuth.OAuthClient. Which one depends on whether you are implementing an OAuth 2.0 or OAuth 1.0 client. This class handles all of the interaction between Neuron ESB and the OAuth provider. In the generic use cases you do not need override any of the logic from the base class. However, if your OAuth provider has requirements that go beyond the basic OAuth standard (i.e. Azure Active Directory and its requirement for a Resource parameter), then you will need to override the necessary base classes. For more information on the Nemiro.Oauth client, see:
Here is an example of an OAuth2Client class for the Client Credentials grant type. The GetAccessToken() method builds the token request makes the call to the authorization server. There are several examples of implementations of the OAuth2Client and OAuthClient classes in the Nemiro.OAuth source code.
public class GenericClientCredentialsGrantOAuth2Client : OAuth2Client
{
private string resource;
public override string ProviderName
{
get { return "Generic Client Credentials Grant OAuth Provider"; }
}
public GenericClientCredentialsGrantOAuth2Client(string tokenUrl, string clientId, string clientSecret, string scope) : base(tokenUrl, tokenUrl, clientId, clientSecret)
{
base.Scope = scope;
base.SupportRefreshToken = false;
}
protected override void GetAccessToken()
{
var parameters = new NameValueCollection
{
{ "grant_type", GrantType.ClientCredentials },
{ "client_id", this.ApplicationId },
{ "client_secret", this.ApplicationSecret }
};
if (base.Scope != null)
parameters.Add("scope", base.Scope);
var result = OAuthUtility.Post
(
endpoint: this.AccessTokenUrl,
parameters: parameters,
authorization: new HttpAuthorization(AuthorizationType.Basic,
OAuthUtility.ToBase64String("{0}:{1}", this.ApplicationId, this.ApplicationSecret))
);
if (result.ContainsKey("error"))
{
this.AccessToken = new OAuth2AccessToken(new ErrorResult(result));
}
else
{
this.AccessToken = new OAuth2AccessToken(result);
}
}
}
Implement the Login class
This class is only necessary if you are implementing the Authorization Code grant type. When using that grant type you need to log-into the authorization server through its Web application and grant access to the registered application. This class inherits Nemiro.OAuth.LoginForms.Login and handles the calls to the authorization server and provides the user interface for entering your credentials and granting access. You typically do not need to override any of the base classes when implementing this class. For more information on the Nemiro.OAuth.LoginForms, see:
For a standard OAuth provider, the Login class should be as simple as this:
public class GenericAuthCodeGrantLogin : Login
{
public GenericAuthCodeGrantLogin(OAuthBase client) : base(client, responseType: "code")
{
}
}
There are several examples of implementations of the Login class included with the Nemiro.OAuth.LoginForms source code.
Implement the OAuthProvider class
Open the class file in your solution (i.e. SampleOAuthProvider). Add these references:
using System;
using System.ComponentModel;
using System.Windows.Forms;
using Nemiro.OAuth;
using Nemiro.OAuth.LoginForms;
using Neuron.Esb.OAuth;
You will only need the reference to System.Windows.Forms if you are using the Authorization Code grant type.
Change the class definition to inherit from OAuthProvider and add the DisplayName attribute which is used by Neuron ESB Explorer when listing the available OAuth providers:
[DisplayName("Generic Client Credentials Grant OAuth Provider")]
public class SampleOAuthProvider : OAuthProvider
{
}
Add the public properties required for the grant type you are implementing. Below are some examples of properties based on the different grant types. You can find implementations of these in the three generic OAuth samples included with the Neuron ESB installation.
Authorization Code
- Client ID
- Client Secret
- Authorization URL
- Token URL
- Redirect URL
- Scope
Client Credentials
- Client ID
- Client Secret
- Token URL
- Scope
Resource Owner Credentials
- Client ID
- Client Secret
- Token URL
- Username
- Password
- Scope
When implementing the properties, you can use the same property attributes that are available for custom process steps and adapters:
- DisplayName
- Description
- PropertyOrder
- EncryptValue
When using the PropertyOrder attribute, you should start with the value of 2. This is because the inherited class OAuthProvider has two public properties – AccessToken and CredentialType, with the PropertyOrder of 0 and 1, respectively.
The EncryptValue attribute will mask the value of the property when displayed in the UI and also encrypt the property value when it is saved in the solution’s XML file.
Here’s an example of a property for the Client Secret:
[DisplayName("Client Secret")]
[Description("The application secret assigned to your app.")]
[PropertyOrder(3)]
[EncryptValue]
public string ClientSecret
{
get
{
return this.clientSecret;
}
set
{
this.clientSecret = value;
}
}
The last thing you need to do is implement the virtual methods GetClient and ClientLogin. The method GetClient returns an instance of your custom OAuth client that you implemented earlier. The method ClientLogin is called when the “Test” button is clicked on the OAuth Provider form in Neuron ESB Explorer. If you are implementing the Authorization Code grant type, this method will show the login form and return the retrieved access token. The GenericAuthCodeGrantOAuthProvider sample demonstrates how to do this. For the other two grant types this method should attempt to retrieve an access token using your OAuth client class, and if successfully received it should be returned. The samples GenericClientCredentialsGrantOAuthProvider and GenericPasswordCredentialsGrantOAuthProvider demonstrate how to do this.
Here is an example of GetClient():
public override OAuthBase GetClient()
{
return new GenericAuthCodeGrantOAuth2Client(this.authorizationUrl, this.tokenUrl,
this.redirectUri, this.clientId, this.clientSecret, this.scope);
}
Here is an example of ClientLogin() for the Authorization Code grant. The first thing this code does is gets an instance of the OAuth client and the OAuth login. Then the login form is displayed, and if an access token is successfully retrieved, it is returned to the caller.
public override AccessToken ClientLogin(Form mainForm)
{
GenericAuthCodeGrantLogin login = null;
try
{
var client = this.GetClient();
login = new GenericAuthCodeGrantLogin(client);
using (login)
{
login.ShowDialog(mainForm);
if (login.IsSuccessfully)
{
return client.AccessToken;
}
else
{
MessageBox.Show(mainForm, String.Format("Unable to obtain an access token - {0}",
login.ErrorMessage), "Test Failed");
}
}
}
catch (Exception ex)
{
MessageBox.Show(mainForm, String.Format("Unable to obtain an access token - {0}", ex.Message), "Test Failed");
}
return null;
}
Here is an example of ClientLogin() for the Client Credentials grant. This code does is gets an instance of the OAuth client and its access token. The get function for AccessTokenValue will make the call to the authorization server to retrieve the access token. If an access token is retrieved it is returned to the caller.
public override AccessToken ClientLogin(System.Windows.Forms.Form mainForm)
{
bool success = false;
try
{
var client = this.GetClient();
var token = client.AccessTokenValue;
if (!String.IsNullOrEmpty(token))
success = true;
if (success)
{
MessageBox.Show(mainForm, "Generic Client Credentials OAuth Test Successful", "Success");
return client.AccessToken;
}
else
{
MessageBox.Show(mainForm, "Unable to obtain an access token - unknown error", "Test Failed");
return null;
}
}
catch (Exception ex)
{
MessageBox.Show(mainForm, String.Format("Unable to obtain an access token - {0}", ex.Message), "Test Failed");
}
return null;
}
The implementation of ClientLogin() for the Resource Owner Credentials grant would be the same as the Client Credentials grant.
Compile and Deploy
Once you’ve compiled the custom OAuth provider, you will copy the assembly to this folder:
<Neuron Install Location>\<Instance>\OAuthProviders
To configure your custom OAuth provider, close and reopen Neuron ESB Explorer and navigate to Security->OAuth Providers. Click on the “New” button and select the custom OAuth provider from the Provider drop-down list.
To debug your provider, you can attach the Visual Studio debugger to NeuronExplorer.exe for design-time debugging and to either ESBService.exe or NeuronProcessHost.exe for runtime debugging.
Read more about Peregrine Connect
-
Rabbit MQ Topics
Introduction Due to the open-source nature of RabbitMQ and constant updates, it is...
-
Port Sharing
One of Neuron ESB’s scalability features is the ability to install multiple...
-
The Integration Journey to...
The Integration Journey to Digital Transformation with Peregrine Connect
-
Saving Time and Money by...
Neuron ESB Application Integration and Web Service Platform: A Real-World Example...
-
Neo PLM
-
Loomis Case Study
Loomis Chooses Peregrine Connect as Their No/Low-Code Integration Platform:...
-
Decision Test Data Mapping
- Use decisions to drive the execution of...
-
Map Testing
Learn how to utilize FlightPath's testing functions...