Authentication

Registration

Access to the API service is protected by our identity provider service.

To register for an account please apply for a trade mark data account.

Note

Currently, even if you plan to use the API service for other data domains than trade mark, please sign up for a trade mark data account. Usage is not restricted to trade mark data.

Access Tokens

To acquire initial access tokens and refresh existing ones, you need to interact with the OpenID Connect token endpoint at the following URL:

https://idp.ipi.ch/auth/realms/egov/protocol/openid-connect/token

The client_id used for this process is the constant string: datadelivery-api-client.

The successful JSON responses from this token endpoint are structured as follows:

{
  "access_token": "HEADER.PAYLOAD.SIGNATURE",
  "expires_in": 720,
  "refresh_expires_in": 360,
  "refresh_token": "HEADER.PAYLOAD.SIGNATURE",
  "token_type": "bearer",
  "not-before-policy": 1559831758,
  "session_state": "UUID",
  "scope": ""
}

This JSON response includes properties such as the access_token, which is used for authentication, and refresh_token, which allows you to obtain a new access token without re-authenticating. The expires_in and refresh_expires_in fields indicate the validity duration (seconds) of the access and refresh tokens, respectively.

Get initial tokens

You can acquire the initial pair of access and refresh tokens by utilizing the OAuth 2.0: Resource Owner Password Credentials Grant procedure.

Important

Do not get new initial tokens for every API request. Instead, reuse the access_token throughout its validity period as specified by the expires_in property in the token endpoint response. To extend the token’s validity, use the refresh_token rather than repeatedly requesting new initial tokens. Failing to reuse tokens appropriately may result in penalties.

Refresh the tokens

Before the refresh_token expires, employ the OAuth 2.0: Refreshing an Access Token procedure to obtain a new pair of access and refresh tokens.

Important

The total lifetime of a session is limited to 600 minutes (10 hours). If, after refreshing, the expires_in value of the new access_token is less than the normal 720 seconds, then start a new session by getting a fresh initial token.

Examples

VS Code REST Client

REST Client: ipi_datadelivery.http
###
# @name login
# @prompt username IDP_USERNAME (email)
# @prompt password IDP_PASSWORD
POST https://idp.ipi.ch/auth/realms/egov/protocol/openid-connect/token
Accept: application/json
Content-Type: application/x-www-form-urlencoded

client_id=datadelivery-api-client
&grant_type=password
&username={{username}}
&password={{password}}

###
@base_url = https://www.swissreg.ch/public
@access_token = {{login.response.body.$.access_token}}
@expires_in = {{login.response.body.$.expires_in}}
@refresh_token = {{login.response.body.$.refresh_token}}
@refresh_expires_in = {{login.response.body.$.refresh_expires_in}}

###
# @name login
POST https://idp.ipi.ch/auth/realms/egov/protocol/openid-connect/token
Accept: application/json
Content-Type: application/x-www-form-urlencoded

client_id=datadelivery-api-client
&grant_type=refresh_token
&refresh_token={{refresh_token}}

###
POST {{base_url}}/api/v1
Authorization: Bearer {{access_token}}
Accept: application/xml
Content-Type: application/xml

<ApiRequest xmlns="urn:ige:schema:xsd:datadeliverycore-1.0.0" uuid="{{$guid}}" timestamp="{{$datetime iso8601}}">
</ApiRequest>

###
POST {{base_url}}/api/v1
Authorization: Bearer {{access_token}}
Accept: application/xml
Content-Type: application/xml

<ApiRequest xmlns="urn:ige:schema:xsd:datadeliverycore-1.0.0" uuid="{{$guid}}" timestamp="{{$datetime iso8601}}">
    <Action type="Echo"/>
    <Action type="UserQuota"/>
</ApiRequest>

Bash shell

# IDP credentials
IDP_USERNAME="${IDP_USERNAME-"$(read -r -p    'IDP_USERNAME: '; echo "${REPLY}")"}" #e.g. "hanna.muster@example.com"
IDP_PASSWORD="${IDP_PASSWORD-"$(read -r -s -p 'IDP_PASSWORD: '; echo "${REPLY}")"}" #e.g. "s3cretPassWord"

# API smoketest
function api_smoketest() {
  API_ENDPOINT="https://www.swissreg.ch/public/api/v1"
  NO_ACTION_REQUEST="<ApiRequest xmlns='urn:ige:schema:xsd:datadeliverycore-1.0.0'/>"
  curl -D /dev/stderr -X POST -H "$API_AUTHORIZATION" -H 'Accept: application/xml' -H 'Content-Type: application/xml' --data-binary "${NO_ACTION_REQUEST}" "${API_ENDPOINT}"

  command -v oha >/dev/null && # https://github.com/hatoo/oha
  oha -c 12 -n 100 -m POST -H "$API_AUTHORIZATION" -H 'Accept: application/xml' -H 'Content-Type: application/xml' -d "${NO_ACTION_REQUEST}" "${API_ENDPOINT}"
}

# Get initial tokens
IDP_RESPONSE="$(curl -s -D /dev/stderr \
  -H "accept: application/json" \
  -d "grant_type=password" \
  -d "client_id=datadelivery-api-client" \
  -d "username=${IDP_USERNAME}" \
  -d "password=${IDP_PASSWORD}" \
  "https://idp.ipi.ch/auth/realms/egov/protocol/openid-connect/token"
)"

## Extract tokens from response
jq '. | .expires_in, .refresh_expires_in' <<<"$IDP_RESPONSE"
IDP_TOKEN="$(jq -r .access_token <<<"$IDP_RESPONSE")"
IDP_REFRESH_TOKEN="$(jq -r .refresh_token <<<"$IDP_RESPONSE")"
API_AUTHORIZATION="Authorization: Bearer ${IDP_TOKEN}"

api_smoketest

# Refresh the tokens
IDP_RESPONSE="$(curl -s -D /dev/stderr \
  -H "accept: application/json" \
  -d "grant_type=refresh_token" \
  -d "client_id=datadelivery-api-client" \
  -d "refresh_token=${IDP_REFRESH_TOKEN}" \
  "https://idp.ipi.ch/auth/realms/egov/protocol/openid-connect/token"
)"

## Extract tokens from response
jq '. | .expires_in, .refresh_expires_in' <<<"$IDP_RESPONSE"
IDP_TOKEN="$(jq -r .access_token <<<"$IDP_RESPONSE")"
IDP_REFRESH_TOKEN="$(jq -r .refresh_token <<<"$IDP_RESPONSE")"
API_AUTHORIZATION="Authorization: Bearer ${IDP_TOKEN}"

api_smoketest

export API_AUTHORIZATION

TypeScript with Deno

TypeScript: ipi_datadelivery.ts
  1import { delay } from "jsr:@std/async/delay";
  2import { promptSecret } from "jsr:@std/cli/prompt-secret";
  3
  4const idpClientId = "datadelivery-api-client";
  5const idpEndpoint =
  6  "https://idp.ipi.ch/auth/realms/egov/protocol/openid-connect/token";
  7
  8const apiEndpoint = "https://www.swissreg.ch/public/api/v1";
  9const noActionRequest =
 10  `<ApiRequest xmlns='urn:ige:schema:xsd:datadeliverycore-1.0.0'/>`;
 11
 12// Utility function to prompt user for input.
 13function getConfig(envVar: string, hide: boolean): string {
 14  const envValue = Deno.env.get(envVar);
 15  if (envValue) {
 16    return envValue;
 17  }
 18  const input = (hide ? promptSecret : prompt)(`${envVar}: `);
 19  if (!input) {
 20    throw new Error(`No input provided for ${envVar}`);
 21  }
 22  return input;
 23}
 24
 25const idpUsername = getConfig("IDP_USERNAME", false);
 26const idpPassword = getConfig("IDP_PASSWORD", true);
 27
 28// Global token storage.
 29// deno-lint-ignore no-explicit-any
 30let tokenData: Record<string, any> = {};
 31
 32// Fetches a token from the IDP using the specified grant type and parameters.
 33async function fetchToken(
 34  grantType: string,
 35  params: Record<string, string>,
 36): Promise<Record<string, unknown>> {
 37  console.log(`Requesting token with grant_type: ${grantType}...`);
 38
 39  const formData = new URLSearchParams({
 40    grant_type: grantType,
 41    client_id: idpClientId,
 42    ...params,
 43  });
 44
 45  const response = await fetch(idpEndpoint, {
 46    method: "POST",
 47    headers: {
 48      "Accept": "application/json",
 49      "Content-Type": "application/x-www-form-urlencoded",
 50    },
 51    body: formData.toString(),
 52  });
 53
 54  if (!response.ok) {
 55    throw new Error(
 56      `Error fetching token: ${response.status} ${response.statusText}`,
 57    );
 58  }
 59  const data = await response.json();
 60
 61  console.log(
 62    "Token expires_in:",
 63    data.expires_in,
 64    ", refresh_expires_in:",
 65    data.refresh_expires_in,
 66  );
 67
 68  return data;
 69}
 70
 71// Get credentials and request the initial token.
 72async function initialToken(): Promise<void> {
 73  console.log("Initial token...");
 74  tokenData = await fetchToken("password", {
 75    username: idpUsername,
 76    password: idpPassword,
 77  });
 78}
 79
 80// Refreshes token and updates tokenData.
 81async function refreshToken(): Promise<void> {
 82  console.log("Refreshing token...");
 83  if (!tokenData.refresh_token) {
 84    throw new Error("No refresh token available");
 85  }
 86  tokenData = await fetchToken("refresh_token", {
 87    refresh_token: tokenData["refresh_token"],
 88  });
 89  console.log("Token refreshed. New access token:", tokenData.access_token);
 90}
 91
 92// Starts a background loop that periodically refreshes the token.
 93export async function startTokenRefreshLoop(): Promise<void> {
 94  await initialToken();
 95  (async function refreshLoop() {
 96    while (true) {
 97      const refreshExpiresIn = tokenData.refresh_expires_in;
 98      // Calculate sleep time as 90% of the current refresh token's lifetime (in seconds)
 99      const sleepSeconds = Math.max(1, Math.floor(refreshExpiresIn * 0.9));
100      console.log(
101        `Sleeping for ${sleepSeconds} seconds before next token refresh...`,
102      );
103      await delay(sleepSeconds * 1000);
104
105      const oldExpires = tokenData.expires_in;
106      try {
107        await refreshToken();
108      } catch (e) {
109        console.error(
110          "Error in refresh-token:",
111          (e as Error).message,
112          "- calling initial-token instead.",
113        );
114        await initialToken();
115      }
116      // If new "expires_in" is lower than the previous value then reinitialize token.
117      if (tokenData.expires_in < oldExpires) {
118        console.log(
119          "New :expires_in is lower than the previous value; fetching new initial token...",
120        );
121        await initialToken();
122      }
123    }
124  })();
125}
126
127// Sends an authenticated POST request to the API endpoint with the given XML body.
128export function apiPost(body: string): Promise<Response> {
129  if (!tokenData.access_token) {
130    throw new Error("No access token available");
131  }
132  const headers = {
133    "Authorization": `Bearer ${tokenData.access_token}`,
134    "Accept": "application/xml",
135    "Content-Type": "application/xml",
136  };
137
138  return fetch(apiEndpoint, {
139    method: "POST",
140    headers,
141    body,
142  });
143}
144
145// Runs an API smoketest by sending a no-action XML request to the API.
146export async function apiSmokeTest(): Promise<void> {
147  console.log("Running API smoketest...");
148  try {
149    const response = await apiPost(noActionRequest);
150    const status = response.status;
151    const responseText = await response.text();
152    console.log("status =", status, "body =", responseText);
153  } catch (e) {
154    console.error("Error in API smoketest:", (e as Error).message);
155  }
156}
157
158if (import.meta.main) {
159  await startTokenRefreshLoop();
160  await delay(1000);
161  console.log("Press Ctrl+C to exit.");
162  while (true) {
163    await apiSmokeTest();
164    await delay(300_000);
165  }
166}

Clojure with Babashka

Babashka: ipi_datadelivery.bb
  1#!/usr/bin/env bb
  2(ns ipi-datadelivery
  3  (:require [babashka.http-client :as http]
  4            [clojure.data.xml :as xml]
  5            [cheshire.core :as json]))
  6
  7(def api-endpoint "https://www.swissreg.ch/public/api/v1")
  8(def idp-endpoint "https://idp.ipi.ch/auth/realms/egov/protocol/openid-connect/token")
  9(def idp-client-id "datadelivery-api-client")
 10
 11(defn- get-config
 12  [env-var hide?]
 13  (or (System/getenv env-var)
 14      (let [prompt-msg (str env-var ": ")]
 15        (if hide?
 16          (println prompt-msg "(input will be visible)")
 17          (print prompt-msg))
 18        (flush)
 19        (read-line))))
 20
 21(def idp-username (get-config "IDP_USERNAME" false))
 22(def idp-password (get-config "IDP_PASSWORD" true))
 23
 24;; Global atom to store token information.
 25(def ^:private token-data (atom {}))
 26
 27(defn- fetch-token
 28  "Fetches a token from the IDP using the specified grant type and parameters.
 29   Returns the parsed JSON response."
 30  [grant-type params]
 31  (println (str "Requesting token with grant_type: " grant-type "..."))
 32  (let [resp (http/post idp-endpoint
 33                        {:headers {"accept" "application/json"}
 34                         :form-params (merge {"grant_type" grant-type
 35                                              "client_id" idp-client-id}
 36                                       params)})
 37        data (-> resp :body (json/parse-string true))]
 38    #_(println (:body resp))
 39    (println "Token expires_in:" (:expires_in data)
 40             ", refresh_expires_in:" (:refresh_expires_in data))
 41    data))
 42
 43(defn- initial-token
 44  "Obtains the initial token using the user credentials and stores it in token-data."
 45  []
 46  (println "Initial token...")
 47  (let [data (fetch-token "password" {"username" idp-username "password" idp-password})]
 48    (reset! token-data data)))
 49
 50(defn- refresh-token
 51  "Attempts to refresh the token. On success, updates token-data."
 52  []
 53  (println "Refreshing token...")
 54  (let [data (fetch-token "refresh_token" {"refresh_token" (:refresh_token @token-data)})]
 55    (reset! token-data data)
 56    (println "Token refreshed. New access token:" (:access_token data))))
 57
 58(defn start-token-refresh-loop
 59  "Starts a background loop that periodically refreshes the token.
 60   It calculates the sleep interval as 90% of the current refresh token's lifetime."
 61  []
 62  (initial-token)
 63  (future
 64    (while true
 65      (let [refresh-expires-in (:refresh_expires_in @token-data)
 66            sleep-seconds (max 1 (int (* refresh-expires-in 0.9)))]
 67        (println "Sleeping for" sleep-seconds "seconds before next token refresh...")
 68        (-> sleep-seconds java.time.Duration/ofSeconds Thread/sleep)
 69        (let [old-expires (:expires_in @token-data)]
 70          (try
 71            (refresh-token)
 72            (catch Exception e
 73              (println "Error in refresh-token:" (.getMessage e) "- calling initial-token instead.")
 74              (initial-token)))
 75          (when (< (:expires_in @token-data) old-expires)
 76            (println "New :expires_in is lower than the previous value; fetching new initial token...")
 77            (initial-token)))))))
 78
 79(defn api-post
 80  "Sends an authenticated POST request to the API endpoint with the given XML body."
 81  [body]
 82  (let [headers {"Authorization" (str "Bearer " (:access_token @token-data))
 83                 "Accept" "application/xml"
 84                 "Content-Type" "application/xml"}]
 85    (http/post api-endpoint {:headers headers :body body})))
 86
 87(start-token-refresh-loop)
 88(-> "PT1S" java.time.Duration/parse Thread/sleep)
 89
 90(defn api-smoketest
 91  "Runs an API smoketest by sending a no-action XML request to the API.
 92   It prints the response status, a UUID from the XML response, and the formatted XML."
 93  []
 94  (println "Running API smoketest...")
 95  (let [no-action-request "<ApiRequest xmlns='urn:ige:schema:xsd:datadeliverycore-1.0.0'/>"
 96        resp (api-post no-action-request)
 97        xml-data (-> resp :body xml/parse-str)]
 98    (println "status=" (:status resp)
 99             "uuid=" (-> xml-data :attrs :uuid)
100             "body=" (xml/indent-str xml-data))))
101
102(println "Press Ctrl+C to exit.")
103(while true
104  (api-smoketest)
105  (-> "PT5M" java.time.Duration/parse Thread/sleep))

Python with Requests

Python: ipi_datadelivery.py
  1#!/usr/bin/env python3
  2import os
  3import threading
  4import time
  5import xml.etree.ElementTree as ET
  6from getpass import getpass
  7import requests
  8from requests.adapters import HTTPAdapter
  9from typing import Any, Dict
 10
 11api_endpoint: str = "https://www.swissreg.ch/public/api/v1"
 12idp_endpoint: str = "https://idp.ipi.ch/auth/realms/egov/protocol/openid-connect/token"
 13idp_client_id: str = "datadelivery-api-client"
 14
 15api_session: requests.Session = requests.Session()
 16api_session.mount("https://", HTTPAdapter(pool_connections=12, pool_maxsize=12, max_retries=0, pool_block=True))
 17
 18def get_config(env_var: str, hide: bool) -> str:
 19    value: str | None = os.getenv(env_var)
 20    if value is None:
 21        prompt: str = f"{env_var}: "
 22        value = (getpass if hide else input)(prompt)
 23    return value
 24
 25idp_username: str = get_config("IDP_USERNAME", False)
 26idp_password: str = get_config("IDP_PASSWORD", True)
 27
 28token_data: Dict[str, Any] = {}
 29token_lock = threading.Lock()
 30
 31def fetch_token(grant_type: str, params: Dict[str, str]) -> Dict[str, Any]:
 32    print(f"Requesting token with grant_type: {grant_type}...")
 33    payload = {"grant_type": grant_type, "client_id": idp_client_id, **params}
 34    resp = api_session.post(idp_endpoint, headers={"accept": "application/json"}, data=payload)
 35    data: Dict[str, Any] = resp.json()
 36    print(f"Token expires_in: {data.get('expires_in')}, refresh_expires_in: {data.get('refresh_expires_in')}")
 37    return data
 38
 39def initial_token() -> None:
 40    print("Initial token...")
 41    new_token = fetch_token("password", {"username": idp_username, "password": idp_password})
 42    with token_lock:
 43        global token_data
 44        token_data = new_token
 45
 46def refresh_token() -> None:
 47    print("Refreshing token...")
 48    with token_lock:
 49        current_refresh = token_data.get("refresh_token", "")
 50        new_data = fetch_token("refresh_token", {"refresh_token": current_refresh})
 51        token_data.update(new_data)
 52        print("Token refreshed.")
 53
 54def token_refresh_loop() -> None:
 55    initial_token()
 56    while True:
 57        with token_lock:
 58            refresh_expires_in = int(token_data.get("refresh_expires_in", 300))
 59            old_expires = int(token_data.get("expires_in", 0))
 60        sleep_seconds: int = max(1, int(refresh_expires_in * 0.9))
 61        print("Sleeping for", sleep_seconds, "seconds before next token refresh...")
 62        time.sleep(sleep_seconds)
 63        try:
 64            refresh_token()
 65        except Exception as e:
 66            print("Error in refresh-token:", str(e), "- calling initial token instead.")
 67            initial_token()
 68        with token_lock:
 69            new_expires = int(token_data.get("expires_in", 0))
 70        if new_expires < old_expires:
 71            print("New expires_in is lower than previous; fetching new initial token...")
 72            initial_token()
 73
 74def start_token_refresh_loop() -> None:
 75    threading.Thread(target=token_refresh_loop, daemon=True).start()
 76
 77def api_post(body: str) -> requests.Response:
 78    with token_lock:
 79        access_token = token_data.get("access_token", "")
 80    headers = {
 81        "Authorization": f"Bearer {access_token}",
 82        "Accept": "application/xml",
 83        "Content-Type": "application/xml"
 84    }
 85    return api_session.post(api_endpoint, headers=headers, data=body)
 86
 87def api_smoketest() -> None:
 88    print("Running API smoketest...")
 89    no_action_request: str = "<ApiRequest xmlns='urn:ige:schema:xsd:datadeliverycore-1.0.0'/>"
 90    resp: requests.Response = api_post(no_action_request)
 91    try:
 92        xml_data = ET.fromstring(resp.text)
 93        uuid = xml_data.attrib.get("uuid", "")
 94        print(f"status={resp.status_code}, uuid={uuid}, body={ET.tostring(xml_data, encoding='unicode')}")
 95    except ET.ParseError as e:
 96        print("XML parse error:", str(e), "body:", resp.text)
 97
 98start_token_refresh_loop()
 99time.sleep(2)
100
101print("Press Ctrl+C to exit.")
102while True:
103    api_smoketest()
104    time.sleep(5 * 60)

PowerShell

PowerShell: Get-IpiDataDeliveryToken
 1function Get-IpiDataDeliveryToken
 2{
 3  param (
 4    [string] $IdpUsername = $env:IDP_USERNAME,
 5    [string] $IdpPassword = $env:IDP_PASSWORD
 6  )
 7    
 8  $TOKEN_ENDPOINT="https://idp.ipi.ch/auth/realms/egov/protocol/openid-connect/token"
 9  $PARAMS = @{
10    grant_type = "password"
11    client_id = "datadelivery-api-client"
12    username = $IdpUsername
13    password = $IdpPassword
14  }
15  $res = Invoke-RestMethod -Method Post -Uri $TOKEN_ENDPOINT -ContentType "application/x-www-form-urlencoded" -Body $PARAMS
16  return $res.access_token
17}
18
19$IdpCredentials = if ($IdpCredentials) { $IdpCredentials } else {
20   Get-Credential -Message "Datadelivery IDP Credentials"
21}
22$env:IDP_USERNAME = $IdpCredentials.UserName
23$env:IDP_PASSWORD = $IdpCredentials.GetNetworkCredential().Password
24$env:IDP_TOKEN = $(Get-IpiDataDeliveryToken)

If your account has multi-factor authentication enabled, the 6-digit time-based one-time password (TOTP) must be provided as well.

PowerShell: Get-IpiDataDeliveryTokenWithTotp
 1function Get-IpiDataDeliveryTokenWithTotp
 2{
 3  param (
 4    [string] $IdpUsername = $env:IDP_USERNAME,
 5    [string] $IdpPassword = $env:IDP_PASSWORD,
 6    [string] $IdpTotpToken = $env:IDP_TOTP_TOKEN,
 7    [string] $IdpTotpSecretBase32 = $env:IDP_TOTP_SECRET_BASE32
 8  )
 9    
10  $TOKEN_ENDPOINT="https://idp.ipi.ch/auth/realms/egov/protocol/openid-connect/token"
11  $PARAMS = @{
12    grant_type = "password"
13    client_id = "datadelivery-api-client"
14    username = $IdpUsername
15    password = $IdpPassword
16  }
17  if ($IdpTotpSecretBase32) {
18    function Get-TOTP {
19      param (
20          [string] $SecretBase32,
21          [int] $TimeStepSeconds = 30,
22          [int] $OTPCodeLength = 6
23      )
24    
25      function Decode-Base32($base32Input) {
26          $num = [Numerics.BigInteger]::Zero
27          foreach ($char in ($base32Input.ToUpper() -replace '[^A-Z2-7]').GetEnumerator()) {
28              $num = ($num -shl 5) -bor ('ABCDEFGHIJKLMNOPQRSTUVWXYZ234567'.IndexOf($char))
29          }
30          [byte[]]$decoded = $num.ToByteArray()
31          if ($decoded[-1] -eq 0) {
32              $decoded = $decoded[0..($decoded.Count - 2)]
33          }
34          [array]::Reverse($decoded)
35          return $decoded
36      }
37      
38      $epochTime = (Get-Date).ToUniversalTime() - ([DateTime]'1970-01-01 00:00:00')
39      $seconds = [math]::Floor($epochTime.TotalSeconds)
40      $counter = [math]::Floor($seconds / $TimeStepSeconds)
41      
42      $counterBytes = [byte[]]::new(8)
43      $cursor = 7
44      while (($counter -gt 0) -and ($cursor -ge 0)) {
45          $counterBytes[$cursor] = ($counter -band 0xFF)
46          $counter = [math]::Floor($counter / (1 -shl 8))
47          $cursor -= 1
48      }
49
50      $hmac = New-Object -TypeName System.Security.Cryptography.HMACSHA1
51      $hmac.Key = Decode-Base32 $SecretBase32
52      $hash = $hmac.ComputeHash($counterBytes)
53    
54      $offset = $hash[19] -band 0xF
55      $fullOTP = ($hash[$offset] -band 0x7F) * (1 -shl 24)
56      $fullOTP += ($hash[$offset + 1] -band 0xFF) * (1 -shl 16)
57      $fullOTP += ($hash[$offset + 2] -band 0xFF) * (1 -shl 8)
58      $fullOTP += ($hash[$offset + 3] -band 0xFF)
59      $modNumber = [math]::Pow(10, $OTPCodeLength)
60      $otp = $fullOTP % $modNumber
61
62      return $otp.ToString("0" * $OTPCodeLength) 
63    }
64
65    $PARAMS += @{
66      totp = $(Get-TOTP -SecretBase32 $IdpTotpSecretBase32)
67    }
68  }
69  if ($IdpTotpToken) {
70    $PARAMS += @{
71      totp = $IdpTotpToken
72    }
73  }
74  $res = Invoke-RestMethod -Method Post -Uri $TOKEN_ENDPOINT -ContentType "application/x-www-form-urlencoded" -Body $PARAMS
75  return $res.access_token
76}
77
78$IdpCredentials = if ($IdpCredentials) { $IdpCredentials } else {
79   Get-Credential -Message "Datadelivery IDP Credentials"
80}
81$env:IDP_USERNAME = $IdpCredentials.UserName
82$env:IDP_PASSWORD = $IdpCredentials.GetNetworkCredential().Password
83$env:IDP_TOTP_SECRET_BASE32 = 'NZEX MODQ JZBG UUSS MFKT I33U OJUV C3BW'
84$env:IDP_TOKEN = $(Get-IpiDataDeliveryTokenWithTotp)