Zum Hauptinhalt springen

AutoFlow-Anmeldedaten

AutoFlow-Anmeldedaten sind ein zentraler, verschlüsselter Speicher für die Authentifizierungsdetails, die deine Flows beim Aufruf externer Systeme brauchen. Der HTTP-Anfrage-Schritt ist der erste Konsument; künftige Schritte für externe Aufrufe werden denselben Speicher nutzen.

Konfiguriere jeden externen Service einmal und referenziere ihn anschließend per Code aus jedem Schritt, der ihn anspricht. Rotierst du einen Schlüssel, wechselst die Umgebung oder änderst ein Geheimnis, geschieht das an einer einzigen Stelle — jeder Flow, der die Anmeldedaten nutzt, übernimmt die Änderung sofort. Geheimnisse erscheinen nie in der Schritt-Konfiguration und nie im Ausführungsprotokoll.

Was du gewinnst

FähigkeitWas das bedeutet
Keine Geheimnisse in FlowsTokens, Passwörter und Client-Secrets liegen verschlüsselt im Speicher, nicht in Schritt-Konfigurationen oder Logs.
Eine Änderung, jeder FlowRotiert ein API-Key, aktualisierst du die Anmeldedaten — alle Flows, die sie nutzen, sind sofort aktuell.
Konsistente AuthentifizierungDer passende Authorization-Header (oder Query-Parameter) wird je Auth-Typ automatisch erzeugt.
Sauberes AusführungsprotokollAuth-Header werden automatisch aus dem Protokoll herausgefiltert.
Allow-List für URLsSind Basis-URLs konfiguriert, prüft AutoFlow jede Anfrage — Anmeldedaten können nicht durch einen falsch konfigurierten oder bösartigen Schritt an eine Spy-URL geraten.
Pro MandantJeder Business-Central-Mandant hat seine eigenen Anmeldedaten. Derselbe Code kann in unterschiedlichen Mandanten auf unterschiedliche Konten zeigen.

Anmeldedaten anlegen

Öffne AutoFlow-Anmeldedaten über Tell-Me und wähle Neu. Die Karte ist in Allgemein, Authentifizierung, Standardheader und Basis-URLs unterteilt.

Allgemein

FeldBedeutung
CodeBis zu 20 Zeichen. Verwende eine Konvention wie MYAPI-PROD oder SHOP-DE-TEST. Diesen Wert siehst du im Lookup des HTTP-Anfrage-Schritts.
BeschreibungFreitext, erscheint in Lookups.
Test-URL (optional)URL, die die Test-Aktion aufruft. Bleibt leer? Dann fällt Test auf die erste Basis-URL zurück. Sinnvoll, wenn keine Basis-URL ein gutes Probe-Ziel ist — dann kannst du hier auf einen Health-Endpunkt zeigen.

Authentifizierung

Wähle den Typ, der zum Zielsystem passt. Die Karte zeigt nur die Felder, die für den gewählten Typ relevant sind.

Eine weiche, gelbe Hinweismeldung erscheint, wenn ein erforderliches Geheimnis noch nicht hinterlegt ist — gespeichert wird die Anmeldedaten-Konfiguration trotzdem; Flow-Ausführungen, die das Geheimnis brauchen, scheitern dann mit einer klaren Fehlermeldung, bis du es nachreichst.

Keine Authentifizierung

Für öffentliche Endpunkte. Es wird kein Geheimnis gespeichert.

API-Key

Die API verlangt einen statischen Schlüssel, der bei jeder Anfrage mitgesendet wird. Konfiguriere:

  • API-Key-Name — der Header- oder Query-Parameter-Name.
  • API-Key-StandortHeader (am häufigsten) oder Query-Parameter.
  • API-Key-Wert — einmal eingeben, dann maskiert. Verschlüsselt gespeichert.

Basic (Benutzer + Passwort)

HTTP-Basic-Authentifizierung. Konfiguriere:

  • Benutzername
  • Passwort — einmal eingeben, dann maskiert.

AutoFlow sendet Authorization: Basic <base64(user:pass)>.

Bearer-Token

Ein statisches Bearer-Token. Konfiguriere:

  • Bearer-Token — einmal eingeben, dann maskiert.

AutoFlow sendet Authorization: Bearer <token>. Tokens beliebiger Länge werden unterstützt (der Speicher chunked transparent).

OAuth 2.0 Client Credentials

Server-zu-Server-OAuth. AutoFlow ruft beim Authorization-Server ein Token ab, cached es und nutzt es bis kurz vor Ablauf wieder. Konfiguriere:

  • OAuth-Token-URL — der Token-Endpunkt des Authorization-Servers.
  • OAuth-Client-ID
  • Client-Secret — einmal eingeben, dann maskiert.
  • OAuth-Scope (optional) — leerzeichengetrennte Liste von Scopes.
  • OAuth-Grant-Type — derzeit nur Client Credentials.
  • OAuth-Client-Credential-Übertragung — wie Client-ID und Secret an den Token-Endpunkt übermittelt werden:
    • Request-Body (formularkodiert) — als client_id=…&client_secret=… im Body. Standard.
    • Authorization-Header (HTTP Basic) — als Authorization: Basic <base64(client_id:client_secret)>. Manche IdPs verlangen das (z. B. ältere ADFS-Instanzen).

Tokens werden verschlüsselt gecached und automatisch erneuert, wenn sie weniger als 60 Sekunden gültig sind. Das expires_in-Feld wird tolerant geparst — sowohl JSON-Integer (3600) als auch JSON-String ("3600") werden akzeptiert; bei fehlendem oder unparsbarem Wert greift ein 3600-Sekunden-Fallback.

Liefert der Token-Endpunkt einen Fehlerstatus, enthält die Fehlermeldung die ersten 200 Zeichen des Antwort-Bodys (laut RFC 6749 ist das bei Client-Credentials-Fehlern error + error_description, niemals ein Token) — so siehst du auf einen Blick, was der IdP wirklich sagt, ohne dass Geheimnisse leaken.

Basis-URLs

Eine Liste erlaubter URL-Präfixe für diese Anmeldedaten. Zwei wichtige Funktionen:

  1. Komfort-Präfix. Verwendet der HTTP-Anfrage-Schritt eine relative URL wie /widgets, präfixt AutoFlow sie mit dem ersten Listeneintrag.
  2. Sicherheits-Allow-List. Verwendet der Schritt eine absolute URL, prüft AutoFlow, ob sie mit einem der konfigurierten Präfixe beginnt. Passt keiner, wird die Anfrage vor dem Senden abgelehnt — das Geheimnis verlässt BC nicht. Das verhindert, dass ein Angreifer (oder ein falsch konfigurierter Flow) das Token an eine Spy-URL wie https://attacker.test/exfil schickt.

Beispiele (mit Basis-URL https://api.beispiel/v1):

Schritt-URLErgebnis
/widgetsPräfixiert → https://api.beispiel/v1/widgets
https://api.beispiel/v1/widgets?page=2Erlaubt (matcht Präfix) ✅
https://api.beispiel/v1Erlaubt (exakter Match) ✅
https://api.beispiel/v123/widgetsAbgelehnt — Grenz-Prüfung an /v1
https://attacker.test/exfilAbgelehnt — Host stimmt nicht

Mehrere Einträge sind unterstützt — sinnvoll, wenn dieselbe Authentifizierung mehrere regionale oder umgebungsspezifische Endpunkte autorisiert (api-eu.beispiel.com, api-us.beispiel.com). Der erste Eintrag gewinnt für die Relativ-URL-Präfixierung; alle Einträge sind gültige Präfixe für die Allow-List.

Die Konfigurationsseite des HTTP-Anfrage-Schritts führt die Allow-List-Prüfung schon zur Designzeit aus — gibst du eine URL ein, die beim Ausführen abgelehnt würde, erscheint eine weiche Warnung direkt unter dem Feld. Die Prüfung beim Ausführen bleibt der harte Wächter.

Lässt du die Liste leer, sind beliebige URLs erlaubt — kein Präfix, keine Prüfung. Verwende das nur, wenn du wirklich offene Anmeldedaten willst und das Risiko akzeptierst, dass eine Fehlkonfiguration das Geheimnis an einen beliebigen Endpunkt schicken könnte.

Plain-HTTP-Warnung

http://-Basis-URLs sind weiterhin zulässig (On-Prem- und Localhost-Workflows brauchen das), aber die Karte zeigt eine weiche Warnung, wenn eine der Basis-URLs ungesichertes HTTP verwendet — Geheimnisse, die über http:// gesendet werden, können auf dem Übertragungsweg abgefangen werden. Verwende https:// für produktive Endpunkte.

Standardheader

Header, die mit dieser Anmeldedaten-Konfiguration immer gesendet werden — z. B. User-Agent, X-Tenant, Accept. Werden auf jede Anfrage angewandt, die diese Anmeldedaten nutzt.

Zwei Einschränkungen:

  • Authorization darf nicht als Standardheader hinzugefügt werden — er ist für den Auth-Typ reserviert.
  • Steht der API-Key der Anmeldedaten auf Header, darf kein Standardheader denselben Namen wie der konfigurierte API-Key-Header tragen — die Auth würde ihn ohnehin überschreiben.

Manuelle Header am HTTP-Anfrage-Schritt überschreiben Standardheader gleichen Namens.

Header-Reihenfolge und Ausführungsprotokoll

Verwendet ein Schritt eine Anmeldedaten-Konfiguration, baut AutoFlow die Header der ausgehenden Anfrage in dieser Reihenfolge zusammen:

  1. Standardheader der Anmeldedaten (niedrigste Priorität).
  2. Manuelle Header des HTTP-Anfrage-Schritts (überschreiben Standardheader gleichen Namens).
  3. Auth-Header des Auth-Typs (gewinnen über alles, auch über manuelle Header).

Auth-Header werden zusätzlich aus dem Ausführungsprotokoll entfernt, damit Geheimnisse dort nie auftauchen. Standard- und manuelle Header werden ganz normal protokolliert.

Bei ApiKey-in-Query wird die URL nach der Basis-URL-Auflösung, aber vor dem Anhängen des Query-Parameters protokolliert — das Geheimnis ist also auf der Drahtleitung, nie im Log.

Die Test-Aktion

Über Test auf der Karte schickst du eine GET-Anfrage an die Test-URL (oder die erste Basis-URL, wenn Test-URL leer ist). Die Ergebnismeldung zeigt den vollständigen HTTP-Status und den vollständigen Response-Body.

Hilfreich, um zu prüfen, ob

  • Basis-URL bzw. Test-URL erreichbar ist,
  • die Authentifizierung wirklich funktioniert (200 oder 401 ist deutlich aufschlussreicher als ein verkonfigurierter Flow).

Lifecycle

Geheimnis rotieren

Karte öffnen, neuen Wert ins Geheimnis-Feld tippen, speichern. Der alte Wert wird im verschlüsselten Speicher überschrieben. Zwischengespeicherte OAuth-Tokens werden nicht automatisch verworfen — über Gespeicherte Geheimnisse löschen erzwingst du einen frischen Tokenabruf.

Alle Geheimnisse löschen

Die Aktion Gespeicherte Geheimnisse löschen entfernt jedes für diese Anmeldedaten gespeicherte Geheimnis dauerhaft (API-Key, Passwort, Bearer-Token, OAuth-Client-Secret, zwischengespeicherte OAuth-Tokens). Die Anmeldedaten selbst bleiben erhalten.

Anmeldedaten umbenennen

Der Code lässt sich über die Standard-BC-Umbenennung ändern. Die Plattform verschiebt verschlüsselte Geheimnisse und Kindzeilen (Standardheader, Basis-URLs) auf den neuen Code und ruft anschließend den Hook OnCredentialRenamed des Auth-Typs auf — Erweiterungs-Auth-Typen können ihre eigenen, unter Custom-Schlüsseln gespeicherten Geheimnisse mitziehen.

Anmeldedaten löschen

Beim Löschen der Anmeldedaten werden alle Geheimnisse und Kindzeilen entfernt und der OnCredentialDeleted-Hook des Auth-Typs ausgeführt. Flows, die noch auf den gelöschten Code referenzieren, scheitern bei der nächsten Ausführung mit einer eindeutigen Fehlermeldung — passe den Schritt an, indem du andere Anmeldedaten auswählst oder die Referenz entfernst.

Mehrere Mandanten

Anmeldedaten sind pro Mandant. Möchtest du denselben Code in mehreren Mandanten verwenden, lege ihn in jedem Mandanten an. Jeder Mandant kann auf ein eigenes Konto zeigen.

Berechtigungen

Drei Berechtigungssätze gehören zum Feature:

BerechtigungssatzZweck
mse365 AF Cred. ReadLesezugriff auf Anmeldedaten und ihre Kindtabellen (wird beim Ausführen von Flows verwendet). Wer Flows ausführt, die Anmeldedaten nutzen, braucht das.
mse365 AF Cred. EditLese- und Schreibzugriff. Schließt Cred. Read ein. Notwendig, um Anmeldedaten anzulegen, zu ändern oder zu löschen.
mse365 AF Cred. RTWrappt Cred. Read. Gedacht zur Aufnahme in den Runtime-/Flow-Ausführungs-Berechtigungssatz des Kunden — wer Flow-Ausführungsrechte bekommt, erbt automatisch den Lesezugriff für die Auflösung von Anmeldedaten. Enthält nicht den Edit-Grant.

Speicherung

Geheimnisse werden mit dem Tenant-Encryption-Key der BC-Plattform AES-verschlüsselt und in IsolatedStorage mit DataScope::Company abgelegt. Da die Verschlüsselungsfunktionen der Plattform Eingaben auf 215 Zeichen begrenzen, werden Werte in ≤ 200-Zeichen-Chunks gesplittet; Lesezugriffe setzen sie transparent wieder zusammen. Klartext landet nie in der Datenbank.

Voraussetzung Tenant-Verschlüsselung

Cryptography Management.EncryptText setzt voraus, dass im BC-Tenant die Datenverschlüsselung aktiviert ist.

  • BC SaaS: Verschlüsselung ist standardmäßig aktiv. Nichts zu tun.
  • On-Prem / Sandbox / Dev-Container: Ein Tenant-Admin muss Verschlüsselung einmalig einschalten — entweder über die Seite Verschlüsselungsverwaltung im BC-Web-Client oder, falls PowerShell-Enable-NavEncryptionKey in containerisierten Umgebungen hängt, durch Veröffentlichen einer einmaligen OnPrem-Target-Bootstrap-App, deren Install-Codeunit Cryptography Management.EnableEncryption(true) aufruft.

Fehlt die Verschlüsselung, scheitert jeder Lese- oder Schreibzugriff mit der Plattform-Meldung An encryption key is required to complete the request. — bewusst harter Fehler statt stillem Klartext-Fallback.

Erweitern: eigene Auth-Typen

Die Liste der Auth-Typen ist erweiterbar. Sinnvoll, wenn das Zielsystem ein Authentifizierungsschema verlangt, das keiner der fünf eingebauten Typen abdeckt — etwa ein Legacy-Webshop, der Header aus einem konfigurierbaren Secret + Zeitstempel + HMAC zusammenbaut.

Was zu implementieren ist

Erweitere das Enum mse365 AF Credential Auth Type um einen neuen Wert, der auf eine Codeunit zeigt, die das Interface mse365 AF ICredentialAuth implementiert:

enumextension 50100 "Acme Hmac Auth" extends "mse365 AF Credential Auth Type"
{
value(50100; AcmeHmac)
{
Caption = 'Acme HMAC';
Implementation = "mse365 AF ICredentialAuth" = "Acme Hmac Auth Impl.";
}
}

codeunit 50100 "Acme Hmac Auth Impl." implements "mse365 AF ICredentialAuth"
{
procedure BuildAuthHeaders(CredentialCode: Code[20]; RequestCtx: Interface "mse365 AF IHttpRequest Ctx."; var Headers: Dictionary of [Text[50], Text[4096]])
begin
// Header aus dem hinterlegten Geheimnis + aktuellem Zeitstempel berechnen.
end;

procedure RewriteUrl(CredentialCode: Code[20]; var Url: Text)
begin
// No-op für Header-basierte Auth; ApiKey-in-Query überschreibt das.
end;

procedure OnCredentialDeleted(CredentialCode: Code[20])
begin
// IsolatedStorage-Einträge unter eigenen Schlüsseln aufräumen.
end;

procedure OnCredentialRenamed(OldCode: Code[20]; NewCode: Code[20])
begin
// IsolatedStorage-Einträge von OldCode auf NewCode umziehen.
// Eingebaute Geheimnisse und Kindtabellen migriert die Plattform selbst.
end;
}

Eigene Konfigurationsfelder

Braucht dein Auth-Typ mehr als nur ein Geheimnis, erweitere Tabelle und Karte:

tableextension 50100 "Acme Hmac Cred Fields" extends "mse365 AF Credential"
{
fields
{
field(50100; "Acme Hmac Algorithm"; Code[10]) { Caption = 'HMAC algorithm'; }
}
}

pageextension 50100 "Acme Hmac Cred Card" extends "mse365 AF Credential Card"
{
layout
{
addlast(Authentication)
{
group(AcmeHmac)
{
Visible = Rec."Auth Type" = Rec."Auth Type"::AcmeHmac;
field("Acme Hmac Algorithm"; Rec."Acme Hmac Algorithm") { }
}
}
}
}

Speichere Geheimnisse über mse365 AF Credential Storage, um dieselbe gechunkte verschlüsselte Speicherung zu erben — keine Eigenbau-Lösung:

var
Storage: Codeunit "mse365 AF Credential Storage";
begin
Storage.SetSecret(CredentialCode, 'AcmeHmacSigningKey', SigningKey);
end;

Storage.DeleteAllSecrets und MoveAllSecrets kennen nur die sechs eingebauten Geheimnisnamen — deshalb existieren OnCredentialDeleted und OnCredentialRenamed, damit Erweiterungen ihre eigenen Schlüssel selbst aufräumen bzw. mitziehen.

Interface-Vertrag

MethodeWann gerufenWas zu tun
BuildAuthHeadersBei jeder ausgehenden AnfrageAuth-Header in das Dictionary schreiben. Hier hinzugefügte Header werden automatisch aus dem Ausführungsprotokoll entfernt.
RewriteUrlBei jeder ausgehenden AnfrageURL mutieren, wenn nötig (z. B. Query-Parameter anhängen). Die URL vor dem Rewrite ist die geloggte.
OnCredentialDeletedAnmeldedaten-Zeile gelöschtEigene IsolatedStorage-Einträge oder Hilfstabellen aufräumen.
OnCredentialRenamedCode der Anmeldedaten umbenanntEigene IsolatedStorage-Einträge von OldCode auf NewCode verschieben.

Die fünf eingebauten Auth-Typen (None / ApiKey / Basic / Bearer / OAuth2CC) implementieren leere Stubs für OnCredentialDeleted und OnCredentialRenamed — die Plattform erledigt das über DeleteAllSecrets / MoveAllSecrets.