10Duke Scale C++ Client
Loading...
Searching...
No Matches
Client Concepts

This documentation gives high level overview of the client and introduces some fundamental concepts.

The client is stateful

Factory-functions are used to create the client. If you only need to checkout/heartbeat/release functionality with license-keys (see Using license key for licensing operations), you can use tenduke::se::TendukeClient. If you are using identity-based licensing, then you need to use tenduke::se::TendukeClientWithOIDCSession.

Both of these clients are stateful, and you must keep the instance alive for the duration of the application.

TendukeClient maintains lease-cache: All leases of licenses checked out are held in memory-based cache. The application developer does not need to have bookkeeping of the leases. All operations on the leases (heartbeat, release) operate through the cache.

TendukeClientWithOIDCSession extends TendukeClient and adds the user login session management. See the links above for further info of the clients.

Saving and restoring the client state

Since the client is stateful, it is recommended that you save the client state to persistent storage. For example, when the application is about to close, you can request the state to be serialized. You can serialize the state after any license related API-call, if you like: This would protect the state against any abnormal ending of the application (e.g. power loss). The state is serialized into a string, which contains JSON-representation of the state. You then store the string to e.g. disk. The JSON format is not documented and any modification of the JSON outside the client is unsupported.

To prevent anyone from tampering the state we strongly recommend that you encrypt the serialized state before storing it. The client currently does not have support for encryption / decryption of the state.

When the application re-starts, it reads the stored state, decrypts it and passes the string in parameter named initialStateAsJSON to the factory funtions which create the client.

The stored state contains OIDC/OAuth configuration, OIDC session state (e.g. access token, id-token), valid (i.e. non-expired) leases of licenses and license token verification keys.

For example, to serialize current state of the client, execute following:

std::shared_ptr<::TendukeClient> tendukeClient = ...;
std::string serializedState = tendukeClient->serializeState();

To restore the client state, pass the serialized state to the factory function when creating the client:

std::string serializedState = ...; // Read the state from somewhere
auto tenduke = ::createTendukeClientForBrowserUsingAutodiscovery(
"stateful-client-demo/0.0.1-alpha-1",
::tenduke::se::BackendConfiguration("https://scale.10duke.com"),
::tenduke::se::ClientPropertiesBuilder().version("0.0.1-alpha-1").build(),
"https://genco.10duke.net/.well-known/openid-configuration",
::BrowserAuthenticationConfig("demo", "http://localhost/login", httpMessageAfterLogin),
serializedState // pass the state here
);

Using 10Duke Scale REST APIs

If you want to use 10Duke Scale REST APIs, which don't have C++ implementation yet, you need to authorize the HTTP-requests using OIDC id-token. This requires using identity-based licensing.

To get the ID-token, use method tenduke::oidc::OIDCState.getIdToken(). Then authenticate the request by adding HTTP header with name Authorization and value IdToken serialized-id-token-value, where serialized-id-token-value is replaced by serialized value of the id-token (method tenduke::oidc::IdToken.getSerialized()).

For example:

std::shared_ptr<::tenduke::se::TendukeClientWithOIDCSession> tendukeClient = ...; // Client created earlier
// Make sure that user has a valid session.
// If the user does not have valid session, this call will either refresh the session or re-login the user
tendukeClient->oidcSession->ensureValidSession();
// Get the id-token:
auto idToken = tendukeClient->oidcSession->getOIDCState()->getIdToken();
auto serializedIdToken = idToken.getSerialized();
auto headerValue = "IdToken " + serializedIdToken;

Errors

Error conditions are reported using C++ exceptions. All exceptions thrown by the client inherit from class tenduke::TendukeException. As a general rule of thumb, if method or function does network access, an exception might be thrown. Parsing JSON or JWTs or doing cryptography operations might throw exceptions. Most methods try to document thrown exceptions, but this is not totally reliable.

Some network exceptions are handled behind-the-scenes, but there are still several conditions, where the exception is propagated to the caller of the method. Network exceptions are caused either by permanent conditions (e.g. invalid URL has been configured) or by temporary conditions (network temporarily down, server in maintenance, server out of resources). There is currently no re-try logic in the client for temporary network issues.

Note that certain licensing-related error conditions do not throw exceptions. For example, if you try to checkout a seat of a license, and there are no seats available, the client does not throw exception. See tenduke::se::licensing::LicensingClient for more information.

See also API error handling in the 10Duke Scale documentation.

High-level vs low-level

The client is built as layers. Most users can use the high-level client, which abstracts away much of the complexities of request authentication. For more control, you may want to use the low-level client. For example, the high level tenduke::se::licensing::DefaultLicensingClient uses lower level tenduke::se::licensing::rest::ScaleLicensingApiImpl. The low-level client performs the actual network call, handling request parametrization and response parsing. The high level client for example manages the OIDC user session state and lease cache.

The low-level clients are currently not thoroughly documented, but we try to keep the interface stable and matching the REST-API.