Authentication#

Some functionality of the freva-rest API and the client library is only accessible after successful authentication. This authentication is realised with OAuth2 token creation. You can create new access and refresh tokens. Refresh tokens can be used to create new access tokens without needing to log in via username and password, thereby minimising the risk of exposing login credentials. Bear in mind that both login and refresh tokens have a limited lifetime.

Generally speaking, you have three options to interact with the authorization system:

  • via the REST API /api/freva-nextgen/auth/v2 endpoints

  • via the freva_client.authenticate() function

  • via the freva-client auth command-line interface

Warning

Starting with version 2506.0.0, the password grant type is no longer supported.

Authentication must now be performed using the authorization code flow. Unless you want to setup a service provider, we advice against using the restAPI endpoints for authentication.

Using the restAPI endpoints#

The API supports token-based authentication using OAuth2. To obtain an access token, clients can use the /api/freva-nextgen/auth/v2/token endpoint by providing valid username and password credentials. The access token should then be included in the authorization header for secured endpoints.

POST /api/freva-nextgen/auth/v2/token#

Create an new login token from a username and password. You should either set a username and password or an existing refresh token. You can also set the client_id. Client id’s are configured to gain access, specific access for certain users. If you don’t set the client_id, the default id will be chosen.

Form Parameters:
  • code – The code received as part of the OAuth2 authorization code flow

  • redirect_uri – The URI to which the authorization server will redirect the user after authentication. It must match one of the URIs registered with the OAuth2 provider

  • refresh-token – The refresh token that is used to create a new token the refresh token can be used instead of authorizing via user creentials.

  • client_id – The unique identifier for your application used to request an OAuth2 access token from the authentication server, this form parameter is optional.

Status Codes:
Response Headers:
  • Content-Typeapplication/json: access and refresh token.

Example Request#

POST /api/freva-nextgen/auth/v2/token HTTP/1.1
host: www.freva.dkrz.de

{
    "refresh-token": "my-token",
}

Example Request#

HTTP/1.1 200 OK
Content-Type: application/json

{
    "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6.."
    "token_type": "Bearer",
    "expires": 1722874908,
    "refresh_token": "eyJhbGciOiJIUzUxMiIsInR5cCIgOiAiSldUIiwia2lkIi.."
    "refresh_expires": 1722876408,
    "scope": "profile email address",
}

Code examples#

Below you can find example usages of this request in different scripting and programming languages

  • Shell
  • Python
  • gnuR
  • Julia
  • C/C++
curl -X POST https://www.freva.dkrz.de/api/freva-nextgen/auth/v2/token \
 -d "username=janedoe" \
 -d "password=janedoe123"
import requests
response = requests.post(
  "https://www.freva.dkrz.de/api/freva-nextgen/auth/v2/token",
  data={"refresh-token": "mytoken"}
)
token_data = response.json()
library(httr)

url <- "https://freva.dkrz.de/api/freva-nextgen/auth/v2/token"
response <- POST(
   "https://www.freva.dkrz.de/api/freva-nextgen/auth/v2/token",
   body = setNames(list("mytoken"), "refresh-token"),
   encode = "form"
)
token_data <- content(response, "parsed")
using HTTP
using JSON

response = HTTP.POST(
  "https://www.freva.dkrz.de/api/freva-nextgen/auth/v2/token",
  body = Dict("refresh-token" => "mytoken")
)
token_data = JSON.parse(String(response.body))
#include <stdio.h>
#include <curl/curl.h>

int main() {
    CURL *curl;
    CURLcode res;

    curl_global_init(CURL_GLOBAL_DEFAULT);
    curl = curl_easy_init();
    if(curl) {
        struct curl_slist *headers = NULL;
        headers = curl_slist_append(headers, "Content-Type: application/x-www-form-urlencoded");

        curl_easy_setopt(curl, CURLOPT_URL, "https://www.freva.dkrz.de/api/freva-nextgen/auth/v2/token");
        curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
        curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "refresh-token=mytoken");

        res = curl_easy_perform(curl);
        curl_easy_cleanup(curl);
    }
    curl_global_cleanup();
    return 0;
}

GET /api/freva-nextgen/auth/v2/status#

Check the status of an access token.

Request Headers:
Status Codes:
Response Headers:
  • Content-Typeapplication/json: access and refresh token.

Example Request#

POST /api/freva-nextgen/auth/v2/status HTTP/1.1
host: www.freva.dkrz.de
Authorization: Bearer your_access_token

Example Request#

HTTP/1.1 200 OK
Content-Type: application/json

{
    "sub": "648692af-aaed-4f82-9f74-2d6baf96f5ea",
    "exp": 1719261824,
    "email": "jane@example.com"
}

Code examples#

Below you can find example usages of this request in different scripting and programming languages

  • Shell
  • Python
  • gnuR
  • Julia
  • C/C++
curl -X GET https://www.freva.dkrz.de/api/freva-nextgen/auth/v2/status \
 -H "Authorization: Bearer YOUR_ACCESS_TOKEN"
import requests
response = requests.get(
  "https://www.freva.dkrz.de/api/freva-nextgen/auth/v2/status",
  headers={"Authorization": "Bearer YOUR_ACCESS_TOKEN"}
)
token_data = response.json()
library(httr)

response <- GET(
   "https://www.freva.dkrz.de/api/freva-nextgen/auth/v2/status",
   add_headers(Authorization = paste("Bearer", "YOUR_ACCESS_TOKEN"))
)
token_data <- content(response, "parsed")
using HTTP
using JSON

response = HTTP.get(
  "https://www.freva.dkrz.de/api/freva-nextgen/auth/v2/status",
  headers = Dict("Authorization" => "Bearer YOUR_ACCESS_TOKEN")
)
token_data = JSON.parse(String(response.body))
#include <stdio.h>
#include <curl/curl.h>

int main() {
    CURL *curl;
    CURLcode res;

    curl_global_init(CURL_GLOBAL_DEFAULT);
    curl = curl_easy_init();
    if(curl) {
        struct curl_slist *headers = NULL;
        headers = curl_slist_append(headers, "Authorization: Bearer YOUR_ACCESS_TOKEN");

        curl_easy_setopt(curl, CURLOPT_URL, "https://www.freva.dkrz.de/api/freva-nextgen/auth/v2/status");
        curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);

        res = curl_easy_perform(curl);
        curl_easy_cleanup(curl);
    }
    curl_global_cleanup();
    return 0;
}

GET /api/freva-nextgen/auth/v2/userinfo#

Get userinfo for the current token.

Request Headers:
Status Codes:
Response Headers:
  • Content-Typeapplication/json: access and refresh token.

Example Request#

POST /api/freva-nextgen/auth/v2/userinfo HTTP/1.1
host: www.freva.dkrz.de
Authorization: Bearer your_access_token

Example Request#

HTTP/1.1 200 OK
Content-Type: application/json

{
    "username": "janedoe",
    "first_name": "Jane",
    "last_name": "Doe",
    "email": "jane@example.com"
    "home": ""
    "is_guest": true
}

Code examples#

Below you can find example usages of this request in different scripting and programming languages

  • Shell
  • Python
  • gnuR
  • Julia
  • C/C++
curl -X GET https://www.freva.dkrz.de/api/freva-nextgen/auth/v2/userinfo \
 -H "Authorization: Bearer YOUR_ACCESS_TOKEN"
import requests
response = requests.get(
  "https://www.freva.dkrz.de/api/freva-nextgen/auth/v2/userinfo",
  headers={"Authorization": "Bearer YOUR_ACCESS_TOKEN"}
)
token_data = response.json()
library(httr)

response <- GET(
   "https://www.freva.dkrz.de/api/freva-nextgen/auth/v2/userinfo",
   add_headers(Authorization = paste("Bearer", "YOUR_ACCESS_TOKEN"))
)
token_data <- content(response, "parsed")
using HTTP
using JSON

response = HTTP.get(
  "https://www.freva.dkrz.de/api/freva-nextgen/auth/v2/userinfo",
  headers = Dict("Authorization" => "Bearer YOUR_ACCESS_TOKEN")
)
token_data = JSON.parse(String(response.body))
#include <stdio.h>
#include <curl/curl.h>

int main() {
    CURL *curl;
    CURLcode res;

    curl_global_init(CURL_GLOBAL_DEFAULT);
    curl = curl_easy_init();
    if(curl) {
        struct curl_slist *headers = NULL;
        headers = curl_slist_append(headers, "Authorization: Bearer YOUR_ACCESS_TOKEN");

        curl_easy_setopt(curl, CURLOPT_URL, "https://www.freva.dkrz.de/api/freva-nextgen/auth/v2/userinfo");
        curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);

        res = curl_easy_perform(curl);
        curl_easy_cleanup(curl);
    }
    curl_global_cleanup();
    return 0;
}

GET /api/freva-nextgen/auth/v2/systemuser#

Get system information for the user in possession of the oauth token.

Request Headers:
Status Codes:
Response Headers:
  • Content-Typeapplication/json: access and refresh token.

Example Request#

POST /api/freva-nextgen/auth/v2/systemuser HTTP/1.1
host: www.freva.dkrz.de
Authorization: Bearer your_access_token

Example Request#

HTTP/1.1 200 OK
Content-Type: application/json

{
    "pw_name": "janedoe",
    "pw_passwd": "\*",
    "pw_uid": 1000,
    "pw_gid": 1001
    "pw_gecos": "Jane Doe",
    "pw_dir":  "/home/jane",
    "pw_shell": "/bin/zsh"
}

Code examples#

Below you can find example usages of this request in different scripting and programming languages

  • Shell
  • Python
  • gnuR
  • Julia
  • C/C++
curl -X GET https://www.freva.dkrz.de/api/freva-nextgen/auth/v2/systemuser \
 -H "Authorization: Bearer YOUR_ACCESS_TOKEN"
import requests
response = requests.get(
  "https://www.freva.dkrz.de/api/freva-nextgen/auth/v2/systemuser",
  headers={"Authorization": "Bearer YOUR_ACCESS_TOKEN"}
)
token_data = response.json()
library(httr)

response <- GET(
   "https://www.freva.dkrz.de/api/freva-nextgen/auth/v2/systemuser",
   add_headers(Authorization = paste("Bearer", "YOUR_ACCESS_TOKEN"))
)
token_data <- content(response, "parsed")
using HTTP
using JSON

response = HTTP.get(
  "https://www.freva.dkrz.de/api/freva-nextgen/auth/v2/systemuser",
  headers = Dict("Authorization" => "Bearer YOUR_ACCESS_TOKEN")
)
token_data = JSON.parse(String(response.body))
#include <stdio.h>
#include <curl/curl.h>

int main() {
    CURL *curl;
    CURLcode res;

    curl_global_init(CURL_GLOBAL_DEFAULT);
    curl = curl_easy_init();
    if(curl) {
        struct curl_slist *headers = NULL;
        headers = curl_slist_append(headers, "Authorization: Bearer YOUR_ACCESS_TOKEN");

        curl_easy_setopt(curl, CURLOPT_URL, "https://www.freva.dkrz.de/api/freva-nextgen/auth/v2/userinfo");
        curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);

        res = curl_easy_perform(curl);
        curl_easy_cleanup(curl);
    }
    curl_global_cleanup();
    return 0;
}

Using the freva-client python library#

The freva-client python library offers a very simple interface to interact with the authentication system.

Client software freva evaluation system framework (freva):

Freva, the free evaluation system framework, is a data search and analysis platform developed by the atmospheric science community for the atmospheric science community. With help of Freva researchers can:

  • quickly and intuitively search for data stored at typical data centers that host many datasets.

  • create a common interface for user defined data analysis tools.

  • apply data analysis tools in a reproducible manner.

The code described here is currently in testing phase. The client and server library described in the documentation only support searching for data. If you need to apply data analysis plugins, please visit the

freva_client.authenticate(*, token_file: str | Path | None = None, host: str | None = None, force: bool = False) Token#

Authenticate to the host.

This method generates a new access token that should be used for restricted methods.

Parameters:
  • refresh_token (str, optional) – Instead of setting a password, you can set a refresh token to refresh the access token. This is recommended for non-interactive environments.

  • host (str, optional) – The hostname of the REST server.

  • force (bool, default: False) – Force token recreation, even if current token is still valid.

Returns:

Token

Return type:

The authentication token.

Examples

Interactive authentication:

from freva_client import authenticate
token = authenticate()
print(token)

Batch mode authentication with a refresh token:

from freva_client import authenticate
token = authenticate(token_file="~/.freva-login-token.json")

Using the command line interface#

Token creation and refreshing can also be achieved with help of the auth sub command of the command line interface

freva-client auth --help

Results

Usage: freva-client auth [OPTIONS]

  Create OAuth2 access and refresh token.

Options:
  --host TEXT        Set the hostname of the databrowser, if not set (default)
                     the hostname is read from a config file
  --token-file TEXT  Instead of authenticating via code based authentication
                     flow you can set the path to the json file that contains
                     a `refresh token` containing a refresh_token key.
  -f, --force        Force token recreation, even if current token is still
                     valid.
  -v                 Increase verbosity  [default: 0]
  -V, --version      Show version an exit
  --help             Show this message and exit.

You can create a token using your user name and password. For security reasons you can not pass your password as an argument to the command line interface. This means that you can only create a new token with help of a valid refresh token in a non-interactive session. Such as a batch job.

Therefore you want to store your token data securely in a file, and use the refresh token to create new tokens:

freva-client auth  > ~/.mytoken.json
chmod 600 ~/.mytoken.json

Later you can use the jq json command line parser to read the refresh token from and use it to create new access tokens.

freva-client auth --token-file ~/.mytoken.json > ~/.mytoken.json

Warning

Avoid storing access tokens insecurely. Access tokens are sensitive and should be treated like passwords. Do not store them in publicly readable plaintext or in code repositories. Instead:

  • Use environment variables or secure storage (e.g. .netrc, OS keychains).

  • Rotate and expire tokens regularly if implementing long-running SPs.

Notes on Code-Based Auth Flow#

Code-based authentication is the only supported method since version 2505.1.0. It follows the OAuth2 Authorization Code Flow and is suitable for both end users and Service Provider (SP) integrations. However, there are important guidelines and limitations you should be aware of.

🔒 Do not call /login or /callback directly#

The endpoints /auth/v2/login and /auth/v2/callback are internal coordination points for the authentication process:

  • /login initiates the code flow by redirecting to the OpenID Connect provider.

  • /callback is the endpoint where the OpenID provider sends the authorization code.

These endpoints are not designed for direct use by end users or typical API consumers. Calling them directly will likely lead to errors or unexpected behaviour.

Instead, you should authenticate using one of the supported client tools:

  • The Python client: via :py:func``freva_client.authenticate``

  • The CLI tool: via freva-client auth

  • The web portal: to manually log in and download a token file

These interfaces abstract away the complexity and ensure the flow is handled securely and correctly.

For Service Providers (SPs)#

If you are building a custom SP (e.g. a web service or interactive tool that needs to act on behalf of a user), then it is appropriate to interact with the code flow endpoints directly — but only with care.

Follow these steps:

  1. Redirect the user to Freva’s /login endpoint:

    GET /api/freva-nextgen/auth/v2/login?redirect_uri=https://your-sp.com/callback HTTP/1.1
    host: www.freva.dkrz.de
    
    • The redirect_uri must be a publicly accessible endpoint on your service that handles the code exchange.

  2. User authenticates via the upstream Identity Provider (e.g., Keycloak).

  3. The Identity Provider redirects back to your service’s /callback endpoint with a code and state query parameter.

  4. Your SP must then POST the code to Freva’s token exchange endpoint:

    POST /api/freva-nextgen/auth/v2/token HTTP/1.1
    host: www.freva.dkrz.de
    Content-Type: application/x-www-form-urlencoded
    
    {
        code=XXX&redirect_uri=https://your-sp.com/callback
    }
    
    • This will return a JSON with access token, refresh token, and expiry info.

  5. Use the access token to authenticate future API requests.

  6. Optionally refresh the token before expiry using:

    POST /api/freva-nextgen/auth/v2/token HTTP/1.1
    host: www.freva.dkrz.de
    Content-Type: application/x-www-form-urlencoded
    
    {
          grant_type=refresh_token&refresh_token=YYY
    }
    

Note

  • You do not need to manage client secrets for browser-based SPs.

  • The redirect_uri must match one of the values registered with the OIDC provider.

  • If you are building a backend-for-frontend (BFF) architecture, handle the token exchange server-side to protect credentials.

This is the recommended approach for implementing a standards-compliant OAuth2 Authorization Code Flow as a Service Provider.