Application Plugin#
Plugin Descriptor interface:
ApplicationPluginDescriptor
Application plugins provide auxiliary functionality to the Curity Identity Server.
They are declared in the Application Profile .
In addition to RequestHandler, application plugins can implement HttpRequestHandler to
handle HTTP requests using HTTP methods (as defined in the
HTTP standard) other than GET and POST.
The Curity Identity Server comes with a few built-in application plugins, as you can find in the Application Plugins section of the documentation.
Using an OAuth Client of the Linked OAuth Profile#
An application plugin can drive an OAuth authorization code flow against the OAuth profile linked to the application profile that hosts the plugin, using a client configured on that linked profile. The plugin does not need to redeclare endpoints, secrets or cryptographic material; it references the client by ID and the SDK takes care of building the authorization URL and exchanging the code for tokens.
To use it, declare a method that returns TokenServiceOAuthClient on the plugin’s
Configuration interface, alongside an HttpClient for back-channel calls and
the other SDK services the handlers below use:
import se.curity.identityserver.sdk.config.Configuration;
import se.curity.identityserver.sdk.config.annotation.DefaultService;
import se.curity.identityserver.sdk.service.ExceptionFactory;
import se.curity.identityserver.sdk.service.HttpClient;
import se.curity.identityserver.sdk.service.SessionManager;
import se.curity.identityserver.sdk.service.oauth.TokenServiceOAuthClient;
public interface MyPluginConfig extends Configuration
{
TokenServiceOAuthClient getOAuthClient();
@DefaultService
HttpClient getHttpClient();
SessionManager getSessionManager();
ExceptionFactory getExceptionFactory();
}
The administrator configures the plugin by picking a client from the linked OAuth profile’s client list. At runtime the plugin uses the service to drive the flow.
The example below illustrates how to use the TokenServiceOAuthClient service from plugin request handlers.
The startAuthorizationCodeFlow method returns an AuthorizationCodeFlow object that contains the authorization URL
and other control data (state, verifier, redirect URI, response mode). The plugin is responsible for persisting this data
until the callback is received. The example uses the session for persistence (AuthorizationCodeFlow extends MapAttributeValue,
so it can be stored directly in a SessionManager); plugins are free to persist via cookie, database, or any other store.
private static final String FLOW_KEY = "oauth-flow";
public final class StartHandler implements RequestHandler<Request>
{
private final TokenServiceOAuthClient _client;
private final HttpClient _httpClient;
private final SessionManager _session;
public StartHandler(MyPluginConfig config)
{
_client = config.getOAuthClient();
_httpClient = config.getHttpClient();
_session = config.getSessionManager();
}
@Override
public Object get(Request request, Response response)
{
AuthorizationCodeFlow flow = _client.startAuthorizationCodeFlow(_httpClient);
_session.put(Attribute.of(FLOW_KEY, flow));
// ... redirect the user-agent to flow.getAuthorizationUrl()
return null;
}
}
public final class CallbackHandler implements RequestHandler<Request>
{
private final TokenServiceOAuthClient _client;
private final HttpClient _httpClient;
private final SessionManager _session;
private final ExceptionFactory _exceptionFactory;
public CallbackHandler(MyPluginConfig config)
{
_client = config.getOAuthClient();
_httpClient = config.getHttpClient();
_session = config.getSessionManager();
_exceptionFactory = config.getExceptionFactory();
}
@Override
public Object get(Request request, Response response)
{
Attribute stored = _session.remove(FLOW_KEY);
if (stored == null)
{
throw _exceptionFactory.badRequestException(
ErrorCode.INVALID_INPUT, "No in-flight authorization code flow");
}
AuthorizationCodeFlow flow = AuthorizationCodeFlow.of(
(MapAttributeValue) stored.getAttributeValue());
Map<String, String> callbackParameters = /* read 'code', 'state', 'iss' from the request */;
OAuthTokens tokens = _client.handleAuthorizationCodeFlowCallback(_httpClient, flow, callbackParameters);
// tokens.accessToken(), tokens.idTokenClaims(), ...
return null;
}
}
PKCE is always used. The SDK validates state and (when present) iss on the
callback automatically. The referenced client must have the
authorization_code capability and be configured with a symmetric key for
client authentication; both are checked the first time the service is used and
surface as a configuration error otherwise. PAR and JARM are handled
transparently when the referenced client requires them.
Extra authorization parameters can be passed via the startAuthorizationCodeFlow(Map, HttpClient)overload; they are appended to the authorization URL as-is.
Whitelisting parameters from end-user input is the plugin author’s responsibility.
AuthorizationCodeFlow carries secret material — the PKCE verifier
and the OAuth state. Persist it through an encrypted, short-lived store
(such as SessionManager or an encrypted cookie). Do not log the flow
object or its underlying attribute map.