This library authenticates by extracting tokens from a TenantCloud browser session via the Chrome DevTools Protocol (CDP), then refreshing and storing them. It does not submit your username and password directly to the old login endpoint.
- Use a Chromium browser: Chrome, Edge, Brave or Chromium; Vivaldi is also detected on Windows and macOS. Firefox and Safari are not supported by this provider.
- An already-open browser is usable only if it exposes a local CDP debugging endpoint at the configured
DebugPort(default 9222) and has a TenantCloud tab open. Being signed in to an ordinary browser window is not sufficient. - Interactive login uses a separate temporary browser profile and a browser-assigned debugging port. Complete sign-in, including any CAPTCHA or MFA, in that window. The temporary browser is closed after token extraction or failure; your normal browser session is not the target of cleanup.
- Browser sign-in requires a graphical session. Do not expose a CDP port to the network: it grants access to browser session data.
For the CLI, run tenantcloud login. Library consumers must opt into interactive login as shown below; it is disabled by default.
- Browser extraction — connects to a Chromium browser's CDP debug port, looks for a tab on
app.tenantcloud.com, and readsaccess_token+fingerprintfromlocalStorageandtc_refresh_tokenfrom cookies - Token refresh — when the JWT expires, the library calls TenantCloud's refresh endpoint with the refresh token and fingerprint
- Persist & loop — refreshed tokens are saved to the configured
ITcTokenStorefor next launch
If AllowInteractiveLogin is enabled and no existing session is found, the provider launches a temporary Chromium instance pointing to the TenantCloud login page. Once you sign in, tokens are extracted automatically.
Tokens can survive across process restarts via ITcTokenStore:
public interface ITcTokenStore
{
Task<TcTokenSet?> LoadAsync(CancellationToken ct);
Task SaveAsync(TcTokenSet tokens, CancellationToken ct);
Task DeleteAsync(CancellationToken ct);
}Uses OS-backed storage:
| OS | Backend |
|---|---|
| Windows | DPAPI-encrypted files in %LOCALAPPDATA%/Yllibed/TenantCloud/ |
| macOS | Keychain (security CLI) |
| Linux | Secret Service through the secret-tool CLI |
Windows tokens are tied to the current user's DPAPI context. On macOS, the user's Keychain must be accessible. On Linux, install secret-tool and provide an accessible, unlocked Secret Service in the user's session; a minimal container or headless runner may not have one. SecureTokenStore.IsSupported identifies the OS, not whether these services are available.
Examples using services assume a ServiceCollection and imports for Microsoft.Extensions.DependencyInjection, Yllibed.TenantCloudClient and Yllibed.TenantCloudClient.Cdp.
services.AddSecureTokenStore();
// With custom options
services.AddSingleton<ITcTokenStore>(new SecureTokenStore(new SecureTokenStoreOptions
{
ServiceName = "MyApp",
AccountKey = "production",
}));Plain JSON file with atomic writes, provided by the CDP package. An option for a library application with provisioned tokens where no credential store is available; it does not remove the need to authenticate or automatically configure the tenantcloud tool:
services.AddSingleton<ITcTokenStore>(new FileTokenStore("/path/to/tokens.json"));Security note: the file contains sensitive refresh tokens. Protect it with appropriate file permissions.
Implement LoadAsync, SaveAsync and DeleteAsync on ITcTokenStore, then register your implementation with dependency injection. Protect refresh tokens in transit and at rest.
The token provider is responsible for supplying Bearer tokens to TcClient:
public interface ITcAuthTokenProvider
{
Task<string?> GetToken(CancellationToken ct);
Task OnTokenRejected(CancellationToken ct, string rejectedToken);
}Provided by the Yllibed.TenantCloudClient.Cdp package. Multi-step strategy:
- In-memory cache (if the JWT is still valid)
- Token store (load + refresh if expired)
- CDP extraction from an existing browser tab
- Interactive login (if
AllowInteractiveLoginis enabled)
services.AddSecureTokenStore();
services.AddSingleton<ITcAuthTokenProvider>(sp => new CdpTokenProvider(new CdpTokenProviderOptions
{
TokenStore = sp.GetRequiredService<ITcTokenStore>(),
DebugPort = 9222,
AllowInteractiveLogin = true,
BrowserExecutablePath = null,
}));
services.AddTenantCloudClient();BrowserExecutablePath = null enables automatic discovery; provide an absolute executable path to select a browser. Options use init properties, so configure them with object initializers rather than assignments inside an Action callback. Use this registration instead of AddCdpTokenProvider() when customizing these options.
Implement the interface above and register it as ITcAuthTokenProvider, followed by AddTenantCloudClient(). On rejection, discard or refresh the rejected token; returning the same rejected token does not enable a successful retry.