Waiting for engine...
Skip to main content

Authentication to your web service

A custom connector for a particular web service needs some mechanism to authenticate HTTP requests. There are many standard authentication schemes that are handled for you with the REST framework. The Rest Client Connector’s connection tab talks about them in detail. The REST framework handles authentication selection in a very specific way that assumes standard fields are being used in the connector-descriptor.xml file, but you can override this functionality. Typically a web service allows a subset authentication schemes, and so developing a REST connector that supports those is imperative. If the target web service allows for authentication with one of the standard provided schemes, then it may be simple enough to configure the connector-descriptor.xml file to include the appropriate authentication schemes.

Let's assume that the service allows for OAuth 2.0 with Client Credentials grant type and basic user authentication. Your descriptor file, in this case, looks like:

Sample connector-descriptor.xml file
<GenericConnectorDescriptor>

<field id="auth" label="Authentication Type" type="string">
<allowedValue label="Basic">
<value>BASIC</value>
</allowedValue>
<allowedValue label="OAuth 2.0">
<value>OAUTH2</value>
</allowedValue>
</field>

<field id="username" label="User" type="string">
<helpText>The username to authenticate with.</helpText>
<visibilityCondition>
<valueCondition fieldId="auth">
<value>BASIC</value>
</valueCondition>
</visibilityCondition>
</field>

<field id="password" label="Password" type="password">
<helpText>The password for authenticating the user.</helpText>
<visibilityCondition>
<valueCondition fieldId="auth">
<value>BASIC</value>
</valueCondition>
</visibilityCondition>
</field>

<field id="preemptive" label="Preemptive authentication" type="boolean">
<defaultValue>false</defaultValue>
</field>

<field id="oauthContext" label="OAuth 2.0" type="oauth">
<oauth2FieldConfig>
<grantType access="hidden">
<allowedValue label="Client Credentials">
<value>client_credentials</value>
</allowedValue>
</grantType>
</oauth2FieldConfig>
</field>

</GenericConnectorDescriptor>

The field ids are special and are handled in the framework explicitly.

If your web service accepts only one type of authentication mechanism, you can either handle this in the descriptor or can override the getAuthenticationType method of the RestOperationConnection class.

Let's assume your web service allows users to authenticate with only user credentials. Your RestOperationConnection class looks like:

Sample RestOperationConnection class
public class SampleRestOperationConnection extends RestOperationConnection {

public SampleRestOperationConnection(OperationContext context) {
super(context);
}

@Override
public AuthenticationType getAuthenticationType() {
return AuthenticationType.BASIC;
}
}

API key authentication

Many web services authenticate requests with one or more named keys passed on every call, typically as a request header (for example, X-API-Key: ...), a query parameter, or a cookie. The REST Client has built-in support for this pattern, so a custom connector that extends the REST Client can enable it through descriptor configuration alone, without overriding any Java.

To expose API key authentication on your connector, add API_KEY as an allowed value of the auth field in your connector-descriptor.xml. Once you select that value, the SDK reads two additional fields that the REST Client descriptor already declares: apiKeyLocation and apiKeyCustomProperties.

Sample connector-descriptor.xml file
<field id="auth" label="Authentication Type" type="string">
<defaultValue>NONE</defaultValue>
<allowedValue label="None">
<value>NONE</value>
</allowedValue>
<allowedValue label="Basic">
<value>BASIC</value>
</allowedValue>
<allowedValue label="OAuth 2.0">
<value>OAUTH2</value>
</allowedValue>
<allowedValue label="API Key">
<value>API_KEY</value>
</allowedValue>
</field>

<field id="apiKeyLocation" type="string" label="API Key Request Location">
<helpText>Select the required location of the API Key in the request.</helpText>
<defaultValue>REQUEST_HEADER</defaultValue>
<allowedValue label="Request Header"><value>REQUEST_HEADER</value></allowedValue>
<allowedValue label="Query Parameter"><value>QUERY</value></allowedValue>
<allowedValue label="Cookie"><value>COOKIE</value></allowedValue>
<visibilityCondition>
<valueCondition fieldId="auth">
<value>API_KEY</value>
</valueCondition>
</visibilityCondition>
</field>

<field id="apiKeyCustomProperties" type="customproperties" label="API Keys">
<helpText>Enter the key value pairs of API Keys that you would like to pass as part of the request.</helpText>
<visibilityCondition>
<valueCondition fieldId="auth">
<value>API_KEY</value>
</valueCondition>
</visibilityCondition>
</field>

When you select API Key in the connection UI, both the location selector and the custom-properties grid become visible. Each row in the grid contributes one key/value pair that the connector injects on every outbound request, in the location chosen by apiKeyLocation.

Because apiKeyCustomProperties is a customproperties field, you can override the keys and values per environment through Environment Extensions, including encrypted values, which makes this auth type suitable for production secrets without checking them into the process.

Behavior by location

LocationWhere keys are injected
REQUEST_HEADERAdded to the request headers alongside any operation-defined headers.
QUERYPrepended to the query string; connection-level keys take precedence over operation-level parameters with the same name.
COOKIEAdded to the request cookie store, scoped to the connection URL's domain and path. Requires the cookieScope field to be set (Global, Connector Shape, or Ignored); if Cookie Scope is empty, the cookie is not sent.

Customizing the generic connector

In most cases, the descriptor configuration above is all you need. If your connector needs to alter how keys are injected, for example, to combine multiple keys into a single header value, or to choose the location dynamically, you can override the relevant methods on RestOperationConnection:

  • getAPIAuthenticationType(): Returns an APIKeyAuthentication enum (REQUEST_HEADER, QUERY, COOKIE, or NONE) derived from the apiKeyLocation property.
  • getAPIAuthenticationKeys(): Returns the user-supplied key/value pairs as a Map<String, String>.
  • isAPIAuthentication(): Returns true when the connection's auth type is API_KEY.
  • isAPIAuthenticationEnabled(APIKeyAuthentication location): A composite check used internally to decide whether to inject keys at a given location.
Sample RestOperationConnection class
public class MyConnection extends RestOperationConnection {

public MyConnection(OperationContext context) {
super(context);
}

@Override
public Map<String, String> getAPIAuthenticationKeys() {
Map<String, String> keys = super.getAPIAuthenticationKeys();
// Example: derive an additional computed key
if (keys != null && isAPIAuthentication()) {
keys.put("X-Request-Signature", sign(keys));
}
return keys;
}
}

Building an application-specific connector

The above configuration suits a general-purpose connector, where you can call any service, specify the location, and type in your own keys. A connector built for one specific application is different: the application accepts the key in exactly one place (a header, a query parameter, or a cookie) and usually under one fixed name. In that case, do not surface the authentication-type dropdown, the location selector, or the key/value grid, because there is only one correct answer for each. Surface only the secret value, and decide the rest in code.

Sample connector-descriptor.xml file

You only need to supply the key value, so the descriptor reduces to a single field. Using type="password" masks it and still allows per-environment, encrypted overrides. There is no auth dropdown, no apiKeyLocation selector, and no apiKeyCustomProperties grid.

<field id="apiKey" type="password" label="API Key">
<helpText>Enter the API Key issued by the application. It is sent as the X-API-Key request header.</helpText>
</field>
Sample RestOperationConnection class

Hard-code the three decisions you no longer make: that this connection always uses an API key, where the key goes, and how the key is built.

public class MyAppConnection extends RestOperationConnection {

public MyAppConnection(OperationContext context) {
super(context);
}

// This connector always uses an API key.
@Override
public boolean isAPIAuthentication() {
return true;
}

// The application only accepts the key in a request header.
@Override
public APIKeyAuthentication getAPIAuthenticationType() {
return APIKeyAuthentication.REQUEST_HEADER;
}

// Build the single key from the one field we surfaced.
@Override
public Map<String, String> getAPIAuthenticationKeys() {
String key = getConnectionProperty("apiKey");
return StringUtil.isBlank(key)
? null
: Collections.singletonMap("X-API-Key", key);
}
}

To inject the key as a query parameter or cookie instead, return APIKeyAuthentication.QUERY or APIKeyAuthentication.COOKIE and use the parameter or cookie name as the map key. For the cookie location, remember the cookieScope requirement noted in the table above.

On this Page