Authentication
Every route except the OAuth ones needs a bearer access token. The login methods in
OpenBiApiClientAuthExtensions get one from the server's oauth/token
endpoint and attach it to the client, so every later call on that client carries it. They also return the
OAuthAccessToken, for its expiry, its scopes and its refresh token.
A client holds one token at a time. To act as two identities at once, use two clients.
As a user
var token = await client.LoginAsync("username", "password", cancellationToken);
The OAuth2 password grant.
As an API key
var token = await client.CreateAccessTokenAsync(apiKeyId, apiKeySecret, cancellationToken: cancellationToken);
The OAuth2 client_credentials grant, for services and scripts. An API key is created in the configurator
or with OpenBiApiClientApiKeyExtensions; its id and secret are the
client id and secret. A scope narrows the token to some of what the key may do.
Windows single sign-on
using var client = new OpenBiApiClient(
new Uri("https://myserver/openbi/api/"),
new HttpClientHandler { UseDefaultCredentials = true });
var token = await client.NegotiateAsync(cancellationToken);
The negotiate grant signs on with Kerberos or NTLM. The message handler answers the server's challenge, so
it has to be allowed to send the current user's credentials. In a browser, the browser does that. The server
has to be configured for single sign-on.
In an app, for its users
An application registered as an OAuth app (BiExcellence.OpenBi.Api.OAuthApps) can use the authorization code flow with PKCE: the user signs in on the open bi server and allows the app, and the app never sees the password.
var pkce = OAuthPkce.Create();
var state = Guid.NewGuid().ToString("N");
// 1. send the user's browser here
var authorizeUri = client.GetAuthorizationUri(appId, redirectUri, pkce, state);
// 2. the browser comes back to redirectUri with ?code=...&state=... - check the state, then
var token = await client.CreateAccessTokenFromAuthorizationCodeAsync(
appId, appSecret, code, redirectUri, pkce.Verifier, cancellationToken);
The secret is null for a public client such as a single page or desktop app. Asking for the openid scope
also returns an OpenID Connect ID token.
Refreshing and signing out
An access token is short-lived (ExpiresIn, in seconds). The password, negotiate and authorization code
grants also return a refresh token, which gets the next access token without signing in again:
token = await client.RefreshAccessTokenAsync(token.RefreshToken!, cancellationToken: cancellationToken);
Every refresh returns a new refresh token. Keep it and drop the old one - using an old one again revokes the whole grant. An API key has no refresh token; it simply asks again.
RevokeTokenAsync ends one grant, SignOutEverywhereAsync every grant of the current user.
Without the login methods
A token obtained some other way is attached with SetAccessToken(string?).