Skip to content

Authentication

This document describes how authentication is handled within the DMA realm and what you need to get started. DMA uses a central authentication server (CAS) to provide OAuth2 authentication to components (applications) where a user login is required.

OAuth2 is a widely used standard for authentication and thus an extensive amount of high-quality documentation exists. In particular, we refer to the official documentation maintained by Aaron Parecki as well as the excellent introductory article on the Okta blog (What the Heck is OAuth?).

In this document, we focus on the subset of the possible authentication mechanisms (grant types) that are relevant in the DMA context. If you are not familiar with OAuth2 concepts, we kindly recommend that you study the aforementioned information sources before you read any further.

Authentication in a Component with User Login

This section describes how you can integrate a component such as a data provisioning service with the DMA authentication server.

Registering your component to use the DMA OAuth authentication service

Components using the DMA authentication service need to be registered with the DMA administrator. To do that, please send an email to support@datamarket.at containing the following information:

  • Name: The name of your component.
  • Description: A short description what your component does.
  • Redirect URI: A URL where the user will be redirected to after successful authentication at the DMA authentication service (e.g. https://myservice.example.com/login).

You will then receive a client_id and client_secret for your component that is needed later for its implementation or configuration.

Grant Type: Authentication Code

When using the grant type authentication_code, the interaction flow is as follows:

  1. The user opens your component's URL in the web browser.
  2. If unauthenticated, the user clicks on a login button and is sent to the login form on the DMA authentication server (can also be implemented as an automatic redirect).
  3. If the user provides the correct credentials, she or he is redirected back to a particular URI of your component with an authentication code attached as query parameter.
  4. Your component exchanges this code for an access token that is then used for all subsequent, authenticated requests.
  5. Your component never gets in touch with the actual user's credentials.

Important note: The exchange of the code for the access token must happen immediately after the code has been received, because the code is valid for only one or two seconds. If you manually test the flow, it may happen that you get an error response if you are not quick enough.

Further information on the authentication code token flow can again be found at the Okta blog (What is the OAuth 2.0 Authorization Code Grant Type?).

Roll-Your-Own Components

If you are not relying on some framework that already supports OAuth2 authentication, here is a detailed description of what you need to do.

First, for the user to log in, your component's UI must provide a link to the authorize endpoint of the DMA authentication server with the following query parameters:

  • response type=code
  • client_id=<ID as provided by the DMA administrator>
  • redirect_uri=<URL of the component that handles the authentication code>
https://cas.datamarket.at/cas/oauth2.0/authorize?response_type=code&client_id=service-id&redirect_uri=https://myservice.example.com/login

When the user has entered the correct credentials, the browser redirects to the URL provided in the redirect_uri with an authentication code provided in the URL parameter code.

https://myservice.example.com/login?code=OC-153-gOw6B9HuW078fVsRnA5PWS6jrU-NmU5V

Your component must now fetch the access token in exchange for the authentication code by calling the accessToken endpoint of the DMA authentication server with the following parameters:

  • grant_type=authorization_code
  • client_id=<ID as provided by the DMA administrator>
  • client_secret=<secret as provided by the DMA administrator>
  • redirect_uri=<URL of the component>
  • code=<value of the code parameter>

Please note that the parameter values must be URL encoded, which can be seen in the example (i.e. redirect_uri).

curl "https://cas.datamarket.at/cas/oauth2.0/accessToken?grant_type=authorization_code&client_id=service-id&client_secret=service-secret&redirect_uri=http%3A%2F%2Fmyservice.example.com%2Flogin&code=OC-153-gOw6B9HuW078fVsRnA5PWS6jrU-NmU5V"

The request may also be performed with POST as method and application/x-www-form-urlencoded in the Content-Type header. This exchange must be performed in the backend part of the component (not the JavaScript running in the browser), otherwise the client_id and client_secret would be exposed.

The response looks like this:

{
    "access_token": "AT-104034-PO4XedS-a58WAvZKVd3k2eCDI7ZIo8hh",
    "token_type": "bearer",
    "expires_in": 28800,
    "refresh_token": "RT-104013-Q92rG6PBmbR9Xq8OpAWV3CqH-68W5NR4"
}

To perform authenticated requests, provide the access token preceded by the string "Bearer " (note the space character) in the Authorization header field.

Authorization: Bearer AT-104034-PO4XedS-a58WAvZKVd3k2eCDI7ZIo8hh

Spring Boot Based Components

In Spring Boot based components leveraging Spring Security OAuth2, integrating with the DMA authentication server is basically a configuration task. In the application properties application.yml (or the according properties file), OAuth2 must be configured as follows:

security:
  oauth2:
    client:
      clientId: <service-id>
      clientSecret: <service-secret>
      accessTokenUri: https://cas.datamarket.at/cas/oauth2.0/accessToken
      userAuthorizationUri: https://cas.datamarket.at/cas/oauth2.0/authorize
      clientAuthenticationScheme: form
    resource:
      userInfoUri: https://usermanagement.datamarket.at/api/me

The framework will take care of the requests, redirections and token management as outlined in the previous section.

More detailed information and example code can be found on relevant websites, such as:

Grant Type: Password / Resource Owner

With this grant type, an access token can be fetched directly from the DMA authentication server by sending the user’s credentials. This can be used for scripts where you need to access resources from DMA components on behalf of your user.

The token is fetched by calling the accessToken endpoint of the DMA authentication server with the following parameters:

  • grant_type=password
  • client_id=<ID as provided by the DMA administrator>
  • username=<username>
  • password=<password>

Example request:

curl "https://cas.datamarket.at/cas/oauth2.0/accessToken?grant_type=password&client_id=service-id&username=jdoe&password=mysecret"

IMPORTANT NOTE: Do not set the client_secret parameter in this request! Otherwise the client will be authenticated, not the user. This is a misleading behavior on the authentication server side, because this is what the "Client Credentials" grant type (not discussed here) is for.

More information on this grant type can also be found at the Okta blog What is the OAuth 2.0 Password Grant Type?.

Grant Type: Refresh Token

An access token is always accompanied by a refresh token with a usually longer validity period than the access token. This serves two purposes: security and convenience.

Re convenience: If the access token expires and the call to the server fails, the system can refresh the access token without user interaction (i.e. logging in again).

Re security: If the short-lived access token is hijacked by a third party, damage can only be done until the access token expires. Only the user having the refresh token can get a new access token (and new refresh token).

The new access token is fetched by calling the accessToken endpoint of the DMA authentication server with the following parameters:

  • grant_type=refresh_token
  • client_id=<ID as provided by the DMA administrator>
  • client_secret=<secret as provided by the DMA administrator>
  • refresh_token=<refresh token that was fetched with the old access token>

Example request:

curl "https://cas.datamarket.at/cas/oauth2.0/accessToken?grant_type=refresh_token&client_id=service-id&client-secret=service-secret&refresh_token=RT-28487-WFWGwU5dkclIOtkCEs71NImNxowglUc5"

Other Token Flows

The "Client Credentials" and "Implicit / Token" grant types are currently not relevant for the DMA platform.

Fetching the User Profile

Once an access token has be received, the user information (profile) can be accessed either directly from the DMA authentication server or the User Management component. The profile on the CAS server is of limited use, because it only contains the ID of the user (e.g. jdoe). Query the User Management component for more information such as roles.

The profile can be fetched from the CAS server by calling the profile endpoint with the query parameter access_token or by setting the request header Authorization to "Bearer <token>".

curl "https://cas.datamarket.at/cas/oauth2.0/profile?access_token=<token>"

or

curl -H 'Authorization: Bearer <token>' “https://cas.datamarket.at/cas/oauth2.0/profile”

The profile can be fetched from the User Management Component by calling the /api/me endpoint with the Authorization header set to "Bearer <token>".

curl -H 'Authorization: Bearer <token>' "https://usermanagement.datamarket.at/api/me"

Logout

To log out (i.e. destroy the session on the DMA authentication server), the component must link to https://cas.datamarket.at/cas/logout with a parameter service that provides a redirect location to some destination URL:

https://cas.datamarket.at/cas/logout?service=https://portal.datamarket.at

Currently, only https://portal.datamarket.at is a valid target URL.

Caveats

Incomplete Logout Due to Token Loss in Component

Context: Authorization code grant type

Problem: If a component stores the access token in a session cookie and the session expires after a while, the access token (and a potentially stored refresh token) is lost. Jumping from the component to the CAS for a re-login results in a redirect back to the component without any user interaction, because a session for the user still exists on the DMA authentication server. The redirect back to the component contains a code parameter as expected. However, when trying to exchange this authorization code for an access token, the DMA authentication server throws an exception.

Solution: when the access token is "lost" in a component, perform a logout on the DMA authentication server to destroy the session (see above) and let the user login again.

Further Information

This is a small set of libraries and examples which may be helpful when using OAuth2 for the first time.