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": ""
}
Status
200
: Successful ResponseStatus
4xx
: Error Response
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
###
# @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
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
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
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
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.
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)