Skip to content

REST API authentication

Apps and scripts calling FMR's secure REST APIs must identify themselves. The way this is done differs depending on the authentication services in use.

Where OIDC is configured as an authentication service, an access token token must be obtained from the identity provider (IdP) and submitted with the FMR REST API request as a 'Bearer' token using the Authorization header.

The following example illustrates the process using a Keycloak IdP:

Register the client with Keycloak

The app or script must first be registered as a client with Keycloak, ensuring the Service Account role is enabled. This activates OAuth 2.0 Client Credentials Grant allowing the client to authenticate to Keycloak using its client-id and client-secret, and retrieve access tokens.

Get an access token

Exchange the app's client-id and client-secret for an access token using the Keycloak token endpoint:

curl -i "http://{keycloak-host}/realms/{realm}/protocol/openid-connect/token" \ # (1)!
-X POST \
-d "grant_type=client_credentials" \
-d "client_id='{client-id}'" \ # (2)!
-d "client_secret='{client-secret}'" # (3)!

  1. {keycloak-host} is the hostname or IP of the Keycloak service {realm} is the realm as configured in Keycloak
  2. {client-id} is OIDC client ID of the script or app as registered with Keycloak
  3. {client-secret} is the client's secret

The response should be a JSON message similar to the following:

{"access_token":"eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJGRVpja0h1NS12VnhGckdwNFdKWm03Q2pDUUtrYlVTVVhCOUFDLWxPZG44In0.eyJleHAiOjE3NzQ1NjQzMTcsImlhdCI6MTc3NDU2NDAxNywianRpIjoiYWYzYjg2ODgtNzlkMi00MjAzLWJiZDYtOGRkMGUzZGE1N2M4IiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo4MTgwL3JlYWxtcy9xdWlja3N0YXJ0X3JlYWxtIiwic3ViIjoiZjJkMDhlNDEtMjAzMS00NGU3LTgyODgtNTZkMzMwMTA4ZGFhIiwidHlwIjoiQmVhcmVyIiwiYXpwIjoic2VjdXJpdHktYWRtaW4tY29uc29sZSIsImFjciI6IjEiLCJhbGxvd2VkLW9yaWdpbnMiOlsiaHR0cDovL2xvY2FsaG9zdDo4MTgwIl0sInNjb3BlIjoicHJvZmlsZSBlbWFpbCIsImNsaWVudElkIjoic2VjdXJpdHktYWRtaW4tY29uc29sZSIsImNsaWVudEhvc3QiOiIxNzIuMTcuMC4xIiwiZW1haWxfdmVyaWZpZWQiOmZhbHNlLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJzZXJ2aWNlLWFjY291bnQtc2VjdXJpdHktYWRtaW4tY29uc29sZSIsImNsaWVudEFkZHJlc3MiOiIxNzIuMTcuMC4xIn0.LcbXGxql1zUTBxDjjC4aw8fx7xxQQ0VChcGE7mF5ZNYWFoxQttRNdu9dyiPLTnOSG2EyzY278bRiGOd2DYmOOLSWfX0PRYAbgvrkcLa32Sqcz6vuUoWuWtMMqXIGt00U_ilHwvhHdgzGfFxDjkhbu8L5bgPkHcpeLxqRoZOh8167wEbTDDGHqgcYpdvDlwy2Sd9vaob_49X5aJo_Nu0WxGjbG93q6zxwgYttDyH-47NDfErUC-ahADysR7ny1eUhy1f6uY172xy5HsR5tVM7nZ2zyNvQB4AUzfDGvv4kiL05--Fhch2_oCLazJkjBHVH4hh2p1f5_ZjhihX2D-RZQA","expires_in":300,"refresh_expires_in":0,"token_type":"Bearer","not-before-policy":0,"scope":"profile email"}
For convenience, save the access token as an environment variable so that it can be used in subsequent REST API calls:
export ACCESS_TOKEN="eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJGRVpja0h1NS12VnhGckdwNFdKWm03Q2pDUUtrYlVTVVhCOUFDLWxPZG44In0.eyJleHAiOjE3NzQ1NjQzMTcsImlhdCI6MTc3NDU2NDAxNywianRpIjoiYWYzYjg2ODgtNzlkMi00MjAzLWJiZDYtOGRkMGUzZGE1N2M4IiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo4MTgwL3JlYWxtcy9xdWlja3N0YXJ0X3JlYWxtIiwic3ViIjoiZjJkMDhlNDEtMjAzMS00NGU3LTgyODgtNTZkMzMwMTA4ZGFhIiwidHlwIjoiQmVhcmVyIiwiYXpwIjoic2VjdXJpdHktYWRtaW4tY29uc29sZSIsImFjciI6IjEiLCJhbGxvd2VkLW9yaWdpbnMiOlsiaHR0cDovL2xvY2FsaG9zdDo4MTgwIl0sInNjb3BlIjoicHJvZmlsZSBlbWFpbCIsImNsaWVudElkIjoic2VjdXJpdHktYWRtaW4tY29uc29sZSIsImNsaWVudEhvc3QiOiIxNzIuMTcuMC4xIiwiZW1haWxfdmVyaWZpZWQiOmZhbHNlLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJzZXJ2aWNlLWFjY291bnQtc2VjdXJpdHktYWRtaW4tY29uc29sZSIsImNsaWVudEFkZHJlc3MiOiIxNzIuMTcuMC4xIn0.LcbXGxql1zUTBxDjjC4aw8fx7xxQQ0VChcGE7mF5ZNYWFoxQttRNdu9dyiPLTnOSG2EyzY278bRiGOd2DYmOOLSWfX0PRYAbgvrkcLa32Sqcz6vuUoWuWtMMqXIGt00U_ilHwvhHdgzGfFxDjkhbu8L5bgPkHcpeLxqRoZOh8167wEbTDDGHqgcYpdvDlwy2Sd9vaob_49X5aJo_Nu0WxGjbG93q6zxwgYttDyH-47NDfErUC-ahADysR7ny1eUhy1f6uY172xy5HsR5tVM7nZ2zyNvQB4AUzfDGvv4kiL05--Fhch2_oCLazJkjBHVH4hh2p1f5_ZjhihX2D-RZQA"

Call the FMR REST API using the access token as proof of identity

Use the access token to call a secure REST API such as structure submit:

curl -X POST \
    -H "Content-Type: application/xml" \
    -H "Action: REPLACE" \
    -H "Authorization: Bearer $ACCESS_TOKEN" \ # (1)!
    -d @structures.xml \ # (2)!
    "http://localhost:8080/ws/secure/sdmxapi/rest"

  1. Pass the access token as proof of identity.
  2. In this example, SDMX-ML structural metadata will be loaded from the file structures.xml.

Basic authentication must be used when authenticating using a directory service.

In the following example, the account's username and password credentials are passed using basic authentication to the structure submit secure REST API:

BASIC_AUTH="{username}:{password}"

curl -X POST \
    -H "Content-Type: application/xml" \
    -H "Action: REPLACE"  \
    -u ${BASIC_AUTH} \
    -d @structures.xml \
    "http://localhost:8080/ws/secure/sdmxapi/rest"

Note

HTTPS should always be used for production services because the basic authentication protocol passes credentials in plain text.

Basic authentication must be used when authenticating using a root superuser account.

In the following example, the root account's username and password credentials are passed using basic authentication to the structure submit secure REST API:

BASIC_AUTH="root:mychosenpassword"

curl -X POST \
    -H "Content-Type: application/xml" \
    -H "Action: REPLACE"  \
    -u ${BASIC_AUTH} \
    -d @structures.xml \
    "http://localhost:8080/ws/secure/sdmxapi/rest"

Note

HTTPS should always be used for production services because the basic authentication protocol passes credentials in plain text.

The client certificate and key must be provided as proof of identity. CA certificates can also be supplied using --cacert if the FMR installation's certificate is signed by an organisation-specific certificate authority.

curl -X POST \
    -H "Content-Type: application/xml" \
    -H "Action: REPLACE"  \
    -d @structures.xml \    
    --cert client.crt \
    --key client.key \
    --cacert ca.crt \
    https://localhost:8080/ws/secure/sdmxapi/rest 

In testing, the server certificate verification may be skipped using the -k argument:

curl -X POST \
    -H "Content-Type: application/xml" \
    -H "Action: REPLACE"  \
    -d @structures.xml \    
    --cert client.crt \
    --key client.key \
    -k \
    https://localhost:8080/ws/secure/sdmxapi/rest 

Where custom authentication is configured using Tomcat Valves, the identification procedure depends on the service in use, so also refer to the Valve's own documentation.

FMR only passes a request to the Valve at two entry points: the /login.html sign-in URL, and /ws/secure/** requests carrying a ticket query parameter. The public SDMX API paths /sdmx/v1/** and /sdmx/v2/** are never passed to the Valve, and an unauthenticated request to a restricted resource on those paths returns 401 with no WWW-Authenticate header.

Session bootstrap

The general pattern is to authenticate once against /login.html, then reuse the resulting session cookie:

# Authenticate using the Valve's scheme and store the session cookie
curl -c cookies.txt --negotiate -u : \
    "http://localhost:8080/login.html"

# Call the API as the authenticated user
curl -b cookies.txt \
    "http://localhost:8080/sdmx/v2/data/dataflow/AGENCY/FLOW/1.0/"

A server-side application acting for several users should hold one session per end user, so that each request is evaluated against that user's own permissions.

Service ticket

Where the Valve validates a ticket presented as a request parameter, such as CAS or ECAS, FMR's secure REST APIs accept it directly:

curl "http://localhost:8080/ws/secure/sdmxapi/rest?ticket=ST-1234-abcdef"

This applies to /ws/secure/** only, and was introduced in FMR 12.3.0.