Authorizing server-to-server communication
This chapter explains with more details the process of configuring Sphinx server when you need server-to-server authorization. In this process there is no "user" involved, and it's the client application itself that authorized directly with the server. This is common practice when your client app is not a UI application where a user "logs in", like in server applications, job runners, daemons, among others. In a server-side application, for example, you have code in one server that needs to be authorized to access another server.
First things first, make sure you have followed the Quickstart chapter thoroughly. It describes the common procedures to setup Sphinx. This chapter just extends what's explained there, with more information that targets server-to-server applications specifically.
Registering a client application
After the server component is setup and database is created, you need to register the client application in Sphinx configuration.
Client applications should be added to TSphinxConfig component using the TSphinxConfig.Clients property. You can do it at design-time, by double-clicking the Clients
property, or from code, calling Clients.Add
. In either case, a new TSphinxClientApp will be created.
Fill in the properties of the added TSphinxClientApp object to properly configure the client application. Please refer to TSphinxClientApp reference for a full list of available properties.
At the very least, for any type of client application you create, you should set the TSphinxClientApp.ClientId property. It uniquely identifies the client, and it is used from the client applications to identify themselves when invoking Sphinx authorization server.
Other commonly used properties are TSphinxClientApp.DisplayName and TSphinxClientApp.ValidScopes.
The following is an example of how to register a server-to-server client application from code. The same properties can be set using the object inspector at design-time.
Client := SphinxConfig1.Clients.Add;
Client.ClientId := 'server';
Client.DisplayName := 'My server app';
Client.RequireClientSecret := True;
Client.AllowedGrantTypes := [TGrantType.gtClientCredentials];
Client.AddSha256Secret(THashSHA2.GetHashBytes(ClientSecret));
Client.ValidScopes.Add('customers');
Client.ValidScopes.Add('orders:read');
Properties ClientId
and DisplayName
simply identify the client application.
The grant type used should be gtClientCredentials
, which is a flow that just provides an access token after the client app sends the client id and client secret.
Since the grant type is client credentials, and the server application is a private/confidential application, RequireClientSecret
should be set to true.
The client secret is provided using the AddSha256Secret
method. You should pass the SHA256 hash of the client secret to it, so clients only authenticate if the SHA256 of the sent client secret matches the one you provide here.
Finally, some arbitrary, application-specific scopes are added to the ValidScopes
property, meaning that such client can only ask for the specified scopes.
Retrieving access token for server-to-server communication
Now the server is prepared to authenticate server-to-server applications, written in any language. With the above client configuration, you can authorize your native application by using the OAuth 2.0 Client Credentials Flow.
The Sphinx server will publish the token endpoint at <base_url>/oauth/token
URL. Send an OAuth 2 token request to the token endpoint passing the client credentials to obtain the access tokens to access the protected API.
Retrieving access token from Delphi applications
If your application is built with Delphi, then TMS Sphinx already provides a high level component TSphinxLogin that will abstract and make it easier the process of obtaining the access token.
Drop the TSphinxLogin component in any form or data module in your application.
You should then configure it setting the following key properties:
- Authority: Should have the base URL of the Sphinx server. For example,
http://localhost:2001/tms/sphinx
. - ClientId: The id of the client you've just previously registered.
- Scope: Spaced-separated list of scope tokens you want to be included in access token to be used with the API. Usually (depends on the server), if left empty, the access token will be provided with all the scopes previously granted to the identified client.
Once the component is configured with the above properties, you can use the RequestToken method to retrieve the access token passing the client secret:
var
TokenResult: ITokenResult;
{...}
TokenResult := SphinxLogin1.RequestToken(ClientSecret);
// Read TokenResult.AccessToken, for example
The function returns an ITokenResult interface with information about the retrieved token, including the AccessToken property which contains the access token.
Authenticating API requests
Once you have the access token (obtained in the previous step), you can use it to authenticate requests to the protected API. Usually it's a bearer token that you should add to the Authorization
HTTP header, prefixed with Bearer
and a space:
Authorization: Bearer <AccessToken>
Adding the above HTTP header to your request should be enough to authenticate and get the response. Please consult your API documentation about how to exactly authenticate to it.