App Registration
Every FlowForger CLI command that talks to Microsoft 365 or Power Automate (--auth, init, pull, push, diff, activate, runs, run-show) and the VS Code extension's data-source features sign in through an app registration in your own Microsoft Entra ID tenant. FlowForger is open source and ships no built-in client ID, so you register one yourself, once, and point the CLI at it in flowforger.config.json.
You need permission to create an app registration (any user can, unless your tenant restricts it). Granting admin consent needs a Global Administrator, Privileged Role Administrator, or Cloud Application Administrator; if that is not you, hand the permission table below to an admin.
1. Create the registration
- Azure Portal → Microsoft Entra ID → App registrations → New registration
- Name:
FlowForger CLI(anything you like) - Supported account types: Accounts in this organizational directory only
- Redirect URI: leave blank
- Register, then copy the Application (client) ID
2. Enable public client flows
Authentication → Advanced settings → Allow public client flows → Yes → Save.
The CLI is a public client: no secret, your identity comes from a device-code browser sign-in.
3. Add delegated permissions
API permissions → Add a permission. Everything is Delegated. Microsoft Graph is the first tab; SharePoint, Dynamics CRM, and Microsoft Flow Service are under APIs my organization uses, searchable by name or App ID.
The CLI requests only what a flow actually uses, so add the rows for the connectors you need, or all of them for a registration that covers every flow. After installing the CLI you can ask it directly:
flowforger scopes my-flow.ff.ts # this flow's permissions
flowforger scopes --all # everything any connector can request
| Connector | API | Delegated permissions |
|---|---|---|
| Always | Microsoft Graph | User.Read |
Dataverse, init, pull, push, diff, activate, runs, run-show, env-var resolution | Dynamics CRM (00000007-0000-0000-c000-000000000000) | user_impersonation |
| SharePoint | SharePoint (00000003-0000-0ff1-ce00-000000000000) | AllSites.Write |
| Office 365 Outlook | Microsoft Graph | Mail.Read, Mail.ReadWrite, Mail.Send, Calendars.Read, Calendars.ReadWrite, Contacts.Read, Contacts.ReadWrite |
| Office 365 Users | Microsoft Graph | User.Read.All, User.ReadWrite, People.Read, Sites.Read.All |
| Office 365 Groups | Microsoft Graph | Group.Read.All, Group.ReadWrite.All, GroupMember.Read.All, GroupMember.ReadWrite.All |
| Microsoft Teams | Microsoft Graph | Team.ReadBasic.All, Team.Create, TeamMember.ReadWrite.All, Channel.ReadBasic.All, Channel.Create, ChannelMessage.Read.All, ChannelMessage.Send, Chat.Create, Chat.Read, Chat.ReadWrite, ChatMember.Read, TeamsActivity.Send, TeamworkTag.ReadWrite, OnlineMeetings.ReadWrite, Calendars.ReadWrite, User.Read.All |
| Word Online, Excel Online, OneDrive for Business | Microsoft Graph | Files.ReadWrite |
runs, run-show, run --replay-run, listCallbackUrl() in a flow | Microsoft Flow Service (7df0a125-d3be-4c96-aa54-591f83ff541c) | User |
Two things people get wrong:
- SharePoint means the SharePoint API, not Graph. The connector calls the SharePoint REST API, which rejects Graph tokens. Graph's
Sites.*permissions do not help; you needAllSites.Writefrom the SharePoint entry. - Add both
ReadandReadWritewhere both are listed. Entra ID consent is per permission, and a read-only flow requests the narrower one.
flowforger scopes <flow> lists the Flow Service permission only when the flow uses listCallbackUrl(). Add it anyway if you will inspect or replay cloud runs with runs, run-show or run --replay-run.
HttpRequest actions calling Graph directly are not scanned. Add what they need here and list it under auth.additionalScopes.graph in the config.
Finish with Grant admin consent for <tenant>. Without it the first sign-in fails with AADSTS65001.
4. Write the config
flowforger init --url https://contoso.crm.dynamics.com --client-id <client-id> --sp-url https://contoso.sharepoint.com
init discovers the tenant ID from the Dataverse URL, does the one-time device-code sign-in, maps the environment's connection references, and writes flowforger.config.json. The auth part looks like this:
{
"auth": {
"clientId": "<client-id>",
"tenantId": "<tenant-id>",
"resources": {
"dataverse": "https://contoso.crm.dynamics.com",
"sharepoint": "https://contoso.sharepoint.com"
}
}
}
The token cache
From here on, --auth on any command is silent: refresh tokens are cached at ~/.flowforger/token-cache.encrypted.json, encrypted for the current OS user with a key kept in the OS credential store (Windows Credential Manager, macOS Keychain, Secret Service on Linux). Anything running as your user can read the cache, the same as with the Azure CLI; copied elsewhere it is unreadable. Delete the file or revoke the user's sessions in Entra ID to invalidate it.
-
Lifetime. A refresh token stays valid for about 90 days of inactivity. After that, the next
--authcommand shows a device-code prompt again and refreshes the cache. -
Several tenants. One cache file serves every config. Sign-ins to other tenants are kept side by side, and the CLI tries the configured tenant's account first.
-
Older versions. Up to 0.5.2 the cache was
~/.flowforger/token-cache.json, which later versions cannot read. The first--authcommand after an upgrade deletes it and shows a device-code prompt once. -
Linux keyring. The cache key is stored by the Secret Service (GNOME Keyring, KWallet or KeePassXC). If the keyring is locked, the desktop shows an unlock dialog (under WSL it appears on the Windows desktop); after 3 seconds the CLI prints a hint to answer it, and after 120 seconds it gives up with an error. On a machine with no desktop session to show that dialog (SSH, CI, containers), or with no Secret Service running, opt into an unencrypted cache file instead:
export FLOWFORGER_TOKEN_CACHE=fileThe cache is then
~/.flowforger/token-cache.plaintext.json, readable only by you (mode 0600). The refresh token is unencrypted on disk, so use this only where the keyring cannot work. -
VS Code. The VS Code extension keeps its own cache,
~/.flowforger/vscode-token-cache.json, so signing in from the CLI does not sign in the extension, and the other way round. -
MCP server.
flowforger mcp --authonly reads the cache and never prompts. Run any--authcommand in a terminal once first.
Troubleshooting
| Error | Fix |
|---|---|
AADSTS65001 not consented | Grant admin consent (step 3), or a permission is missing: run flowforger scopes <flow> |
AADSTS7000218 client_secret required | Enable Allow public client flows (step 2) |
AADSTS700016 application not found | clientId and tenantId in the config do not belong together |
SharePoint 401 after a successful sign-in | Registration has Graph Sites.* instead of SharePoint AllSites.Write |
Dataverse 403 | Your user needs a security role in the environment (for example System Customizer) |
--auth requires a config file | Run from the directory containing flowforger.config.json, or pass --config |
The system keyring did not respond within 120s | Answer the keyring unlock dialog, or on a headless machine set FLOWFORGER_TOKEN_CACHE=file (token cache) |
The encrypted token cache used by --auth could not be loaded (Linux) | No Secret Service is running: start a keyring daemon (GNOME Keyring, KWallet, KeePassXC), or set FLOWFORGER_TOKEN_CACHE=file |
runs/run-show: The flow-service token was refused | Add the Microsoft Flow Service User permission (step 3) and grant consent; the flow must also be visible to you |
Next: Quick Start to write and run a first flow, or the CLI reference.