10Duke Enterprise C++ SDK
Loading...
Searching...
No Matches
Use identity-based licensing

10Duke Enterprise supports identity-based licensing for users: users authenticate themselves and every operation tracks the user's identity. For authentication, 10Duke Enterprise uses Open ID Connect (OIDC), an authentication framework built on OAuth 2.0. To use identity-based licensing, you need an OIDC-based identity provider service. If you don't have one configured, contact 10Duke sales for options.

The 10Duke Enterprise C++ SDK provides the following types of OIDC authentication:

  • Browser-based authentication where the client uses the default OS browser to perform the login.
  • OAuth "Device Authorization Grant" authentication. This is primarily intended for scenarios where the device lacks a browser. The user authenticates out-of-band using a browser on another platform.
  • OAuth "Client Credentials Grant" that is most suitable for authenticating servers and devices.
  • OAuth "Resource Owner Password Credentials Grant" that we do not recommend, but is available for legacy use cases.

In all cases, the client automatically manages the login session whenever an API method requiring authorization is used:

  • If a user has not yet logged in, the first API call automatically triggers a login.
  • If a user has logged in, but the access token has expired, the client automatically performs an access token refresh and executes the API call.
  • If the refresh fails, the client performs a relogin for the user.
  • If an HTTP request fails because the access token is no longer valid (for example, it has expired or has been invalidated in the backend), the client automatically tries to refresh the token. If the refresh is successful, the client re-executes the original request. If the refresh fails, the client performs a re-login for the user.

You do not need to explicitly start login or refresh the session. You can register a callback that gets notified when certain login-related events (for example, login is starting) occur, see Registering session event listener for details.

See also the client concepts and the 10Duke Enterprise official documentation for an overview of identity-based licensing.

To create the client for browser-based authentication:

To create the client for device authentication, use the factory functions:

To create the client for Client Credentials Grant, use the methods from factory tenduke::ee::CCGClientFactory

To create the client for Resource Owner Password Credentials grant, use the methods from factory tenduke::ee::ROPGClientFactory.

Note the following client limitations:

  • Only OIDC ID tokens signed with RSA-keys using (RS256) are supported.
  • Only OAuth "Authorization Code Grant with PKCE" is supported (see RFC 7636).
  • Only a single OIDC ID token verification key is supported.
  • Client Credentials Grant does not provide an ID token.

All these work with 10Duke Identity Provider.

Browser-based authentication

The 10Duke Enterprise C++ SDK provides browser-based OIDC authentication by default using the operating system default browser and "loopback interface redirection". When a user is authenticated, the client opens the default OS browser and starts the login flow with the OIDC provider. The client simultaneously opens a simple local HTTP server used to detect when the login is complete. After completing the login, the OIDC server issues an HTTP redirect to a preconfigured URL (the redirect URI) in the browser. For details see RFC 8252: 7.3 Loopback Interface Redirection.

The client must be configured with an HTTP message served by the HTTP server after the login is complete. The HTTP message is a full HTTP response with a status line, headers, and a response message entity. This allows, for example, using an HTTP redirect to navigate to an external site after login.

To create a client for browser-based authentication, see the below example:

std::string httpMessageAfterLogin =""
"HTTP/1.1 200 OK\n"
"Content-Type: text/html; charset=utf-8\n"
"\n"
"<html>\n"
"<head>\n"
" <title>Login successful, you can close the tab</title>\n"
"</head>\n"
"<body>\n"
" <H1>Login successful</H1>\n"
"</body>\n"
"</html>";
auto tendukeClient = ::tenduke::ee::createClientUsingAutodiscovery(
"browser-authentication-client-demo/0.0.1-alpha-1/mac",
::tenduke::ee::ClientProperties::Builder()
.hardwareId("simulated-hardware-id")
.build(),
"https://genco.10duke.net",
tenduke::oidc::osbrowser::BrowserAuthenticationConfig(
"demo-client", // oauthClientId, this value must also be configured in OIDC backend
"http://localhost/oidc/login", // oauthRedirectUri, this value must also be configured in OIDC backend
httpMessageAfterLogin // the HTTP message
)
);

Note that the redirect URI must start with http://localhost.

Device authentication

If the device running the client lacks a browser, or using the browser is awkward, the authentication can be performed using the "Device Authorization Grant" (or device flow). To start the user login, the device shows an authentication URL and a user code to the user. Using another device (for example, a computer or tablet), the user starts authentication by navigating to the given URL and entering the user code. Once the authentication is complete, the client is notified and a user session is set up.

For details of the Device Authorization Grant, see RFC 8628.

When authenticating with device flow, the client must be configured with a callback that is called when the client needs to display the URL for the user. You must implement the display of the relevant information.

Example:

class OnDeviceAuthorizationResponseReceived : public ::tenduke::oauth::device::OAuthDeviceAuthorizationResponseReceived {
public:
void callback(const tenduke::oauth::device::DeviceAuthorizationResponse &response) override {
std::cout << std::endl
<< "Please open this address in your browser:" << std::endl
<< " " << response.verificationUri << std::endl
<< std::endl
<< "Authenticate yourself and enter following code when prompted:" << std::endl
<< " " << response.userCode << std::endl
<< std::endl
<< "Full URL for copy-pasting:" << std::endl
<< " " << response.verificationUriComplete << std::endl
;
}
};
// later in code:
auto callback = std::make_shared<OnDeviceAuthorizationResponseReceived>(); // Keep handle of this for the duration of the client!
auto tendukeClient = ::tenduke::ee::createClientForDeviceUsingAutodiscovery(
"cpp-licensing-demo/0.0.0", // Identifies this client software
::ClientProperties::Builder()
.hardwareId("simulated-hw-id") // Hardware id
.build(),
"https://your-company-name.10duke.net", // URL of the deployment
::DeviceAuthenticationConfig(
"cpp-device-grant", // OAuth client-id, configured in the deployment
*callback
)
);

Authentication using OAuth Client Credentials Grant

If the entity to be authenticated is a device or server, you can use OAuth Client Credentials Grant. The authenticated actor is the OAuth client, not a user, and thus, the ID token is not available. This is by design.

The 10Duke Enterprise documentation describes the Client Credentials Grant. For further details, such as use cases or how to configure the backend for the Client Credentials Grant, contact 10Duke support.

To set up the client to authenticate with Client Credentials:

auto tendukeClient = ::tenduke::ee::CCGClientFactory("cpp-licensing-demo/0.0.0").createClientUsingAutodiscovery(
::ClientProperties::Builder()
.hardwareId("simulated-hw-id") // Hardware id
.build(),
"https://url-of-the-deployment", // URL of the deployment
::CCGAuthenticationConfig(
"simulated-oauth-client-id", // OAuth client id, configured in the deployment. This is used as a username
"simulated-oauth-secret" // OAuth client secret, configured in the deployment This is used as a password
)
);

Authentication using OAuth Resource Owner Password Credentials Grant

We do not recommend the use of OAuth Resource Owner Password Credentials Grant as this grant is disallowed in OAuth 2.0 Security Best Current Practice.

To use this authentication method, create an implementation of tenduke::oauth::ropg::ResourceOwnerPasswordCredentialsProvider and register an instance of it when creating the client (see below for an example). Because the client maintains the state automatically, it executes the callback to provide the authentication credentials when the client determines that a user needs to log in.

If authentication fails because of invalid credentials, the client internally retries the authentication request by first executing the callback again and then re-executing the request with the new credentials. The client has a maximum number of retries after which tenduke::oauth::OAuthInvalidGrant is thrown. You can configure the maximum number of allowed retries when creating the client.

See the 10Duke Enterprise documentation for more details of the Resource Owner Password Credentials Grant.

To create a client that authenticates users with Resource Owner Password Credentials Grant:

// Sample callback:
class SampleCredentialsProvider : public ::tenduke::oauth::ropg::ResourceOwnerPasswordCredentialsProvider
{
public:
::tenduke::oauth::ropg::ResourceOwnerPasswordCredentials getCredentials() const override
{
std::string username;
std::string password;
std::cout << "Enter username:" << std::endl;
std::getline(std::cin, username);
std::cout << "Enter password:" << std::endl;
std::getline(std::cin, password);
return ::tenduke::oauth::ropg::ResourceOwnerPasswordCredentials(username, password);
}
};
SampleCredentialsProvider credentialsProvider; // Keep instance of this alive for the duration of the client
// Create the client:
auto tendukeClient = ::tenduke::ee::ROPGClientFactory("cpp-licensing-demo/0.0.0").createClientUsingAutodiscovery(
::ClientProperties::Builder()
.hardwareId("simulated-hw-id") // Hardware id
.build(),
"https://url-of-the-deployment", // URL of the deployment
::ROPGAuthenticationConfig(
credentialsProvider, // Provides the authentication credentials
"simulated-oauth-client-id", // OAuth client id, configured in the deployment
"simulated-oauth-secret", // OAuth client secret, configured in the deployment
3 // Max login attempts, 0 is "unlimited" (::ROPGAuthenticationConfig::DEFAULT_LOGIN_ATTEMPTS)
)
);

Register session event listener

The client automatically manages the user login session. It performs the login (either by opening a browser or by device flow callback) when you use an API that requires a valid user login session, and the user has not yet logged in, or when the login session has expired. The client also refreshes the login session automatically when required. You do not need to trigger the login manually.

You can be notified when the login is starting or complete, or the user session has been refreshed. For example, when the login is complete, you can bring your application to the foreground. This is useful as the browser usually opens on top during the login.

To get the notifications, register the instance of tenduke::oidc::OIDCSessionEventListener when creating the client. You can also inherit from tenduke::oidc::DefaultOIDCSessionEventListener, which has empty default implementations for all the callback methods. To configure the listener, use the oidcSessionConfiguration parameter in the OIDC authentication configuration, see below for examples.

A sample listener:

class SampleSessionEventListener : public ::tenduke::oidc::DefaultOIDCSessionEventListener {
public:
void loginStarting() override {
std::cout << "LOGIN STARTING" << std::endl;
}
void loginComplete(const ::OIDCState &state) override {
std::cout << "LOGIN COMPLETE (access-token: " << state.getAccessToken() << ")" << std::endl;
}
};

When creating a client for browser-based authentication, register the listener using the oidcSessionConfiguration parameter of tenduke::oidc::osbrowser::BrowserAuthenticationConfig:

auto tendukeClient = ::tenduke::ee::createClientUsingAutodiscovery(
"browser-based-client-demo/0.0.1-alpha-1/mac",
::tenduke::ee::ClientProperties::Builder()
.hardwareId("simulated-hardware-id")
.build(),
"https://genco.10duke.net",
::tenduke::oidc::osbrowser::BrowserAuthenticationConfig(
"demo-client",
"http://localhost/oidc/login",
httpMessageAfterLogin,
::OIDCSessionConfiguration::Builder() // use builder to configure oidcSessionConfiguration
.listenEventsWith(sessionEventListener) // register the custom session event listener
.build()
)
);

For fully working sample, see identity_based_client_example.cpp under examples.

Examples

Here are some examples on how to work with the client. For further details and complete API documentation, see tenduke::ee::TendukeClient.

Licensing operations

Check out licenses:

auto checkoutResponse = tendukeClient->licensing->checkoutLicenses()
.version("1.0.0") // Set default version to check out, this applies to all following licenses,
// unless overridden at license level. Version is optional.
.seat("sample-product") // Check out one seat of "sample-product" with default version
.execute();
// Check for failures:
if (checkoutResponse.hasErrors()) {
// handle errors
}

Renew leases of the checked out licenses: (NOTE: A renewal changes the lease IDs. The returned leases replace the original leases.)

auto renewResponse = tenduke->licensing->renewLeases()
.leases(result.leases)
.execute();
// Check for failures:
if (renewResponse.hasErrors()) {
// handle errors
}

To release the licenses (NOTE A renewal has changed the lease IDs.)

auto releaseResponse = tendukeClient->licensing->releaseLicenses()
.leases(renewResponse.leases)
.execute();

Work with OIDC session

Get current OAuth access token for authenticating requests to other 10Duke Enterprise APIs:

std::string accessToken = tendukeClient->oidcSession->getAccessToken();