A
Builder design pattern used to
construct
com.okta.sdk.client.Client instances.
The
ClientBuilder is used to construct Client instances with Okta credentials,
Proxy and Cache configuration. Understanding caching is extremely important when creating a Client instance, so
please ensure you read the Caching section below.
Usage
The simplest usage is to just call the
#build() method, for example:
Client client =
Clients.builder().
#build();
This will:
- Automatically enable a simple in-memory
CacheManager for enhanced performance (but please read
the Caching section below for effects/warnings).
- Automatically attempt to find your API credentials values in a number of default/conventional locations and then use
the discovered values. Without any other configuration, the following locations will be each be checked,
in order:
- The environment variable
OKTA_CLIENT_TOKEN. If either of
these values are present, they override any previously discovered value.
- A yaml file that exists at the file path or URL specified by the
okta.client.filesystem property. If this file exists and any values are present, the values override any
previously discovered value. The
okta.client.file system property String can be an
absolute file path, or it can be a URL or a classpath value by using the
url: or
classpath: prefixes respectively. Default value is {code ~/.okta/okta.yaml}.
- The system properties
okta.client.token. If this value is present, it will override any
previously discovered values.
SECURITY NOTICE: While the
okta.client.token system property may be used to represent your
API Key Secret as mentioned above, this is not recommended: process listings on a machine will expose process
arguments (like system properties) and expose the secret value to anyone that can read process listings. As
always, secret values should never be exposed to anyone other than the person that owns the API Key.
While an API Key ID may be configured anywhere (and be visible by anyone), it is recommended to use a private
read-only file or an environment variable to represent API Key secrets. Never commit secrets to source code
or version control.
Explicit API Key Configuration
The above default API Key searching heuristics may not be suitable to your needs. In that case, you will likely
need to explicitly configure your API Key. For example:
ClientCredentials clientCredentials = new TokenClientCredentials("apiToken");
Client client =
Clients.builder().setClientCredentials(clientCredentials).build();
*
Caching
NOTE: Caching support is currently in Alpha status.
By default, a simple production-grade in-memory
CacheManager will be enabled when the Client instance is
created. This
CacheManager implementation has the following characteristics:
- It assumes a default time-to-live and time-to-idle of 1 hour for all cache entries.
- It auto-sizes itself based on your application's memory usage. It will not cause OutOfMemoryExceptions.
(It does this by retaining only 100 strong references to cached objects. Additional cached objects are
weakly referenced, ensuring the garbage collector can evict weakly referenced cache entries if it needs
more memory for your application.).
but, please note:
The default cache manager is not suitable for an application deployed across multiple JVMs.
This is because the default implementation is 100% in-memory (in-process) in the current JVM. If more than one
JVM is deployed with the same application codebase - for example, a web application deployed on multiple identical
hosts for scaling or high availability - each JVM would have it's own in-memory cache. Multiple disconnected caches
for the same data will cause cache coherency problems and likely cause errors in your application!
As a result, if your application that uses a Okta Client instance is deployed across multiple JVMs, you
SHOULD ensure that the Client is configured with a
CacheManager implementation that uses coherent and
clustered/distributed memory.
Custom CacheManager
If you want to specify a custom
CacheManager implementation:
CacheManager cacheManager = new MyCacheManagerImplementation();
Client client =
com.okta.sdk.client.Clients.builder().setCacheManager(cacheManager).build();
Application deployed on a single JVM
If your application is deployed on a single JVM and you still want to use the default
CacheManager implementation, but the default cache configuration does not meet your
needs, you can specify a different configuration. For example:
import static com.okta.sdk.cache.Caches.*;
...
com.okta.sdk.cache.Caches.
com.okta.sdk.cache.Caches#newCacheManager().withDefaultTimeToLive(300, TimeUnit.SECONDS) // default
.withDefaultTimeToIdle(300, TimeUnit.SECONDS) //general default
.withCache(
com.okta.sdk.cache.Caches#forResource(Class)(Account.class) //Account-specific cache settings
.withTimeToLive(1, TimeUnit.HOURS)
.withTimeToIdle(30, TimeUnit.MINUTES))
.withCache(
com.okta.sdk.cache.Caches#forResource(Class)(Group.class) //Group-specific cache settings
.withTimeToLive(2, TimeUnit.HOURS))
//... etc ...
.build(); //build the CacheManager
See the
com.okta.sdk.cache.Caches utility class and the
com.okta.sdk.cache.CacheManagerBuilder docs for more information.
Application deployed across multiple JVMs
If your application is deployed across multiple JVMs (for example a web app deployed on multiple web nodes for
scale and/or high availability), you will likely need to specify a custom
CacheManager implementation that is based on network distributed/coherent memory. For example, an
implementation might delegate to a Hazelcast or
Redis cluster. For example, if using the out-of-the-box Hazelcast plugin:
import com.okta.sdk.hazelcast.HazelcastCacheManager;
// ... etc ...
//Get a HazelcastInstance from your app/config. This can be a HazelcastClient instance too:
HazelcastInstance hazelcastInstance = getHazelcastInstanceOrHazelcastClient();
CacheManager cacheManager = new HazelcastCacheManager(hazelcastInstance);
Client client =
com.okta.sdk.client.Clients.builder().setCacheManager(cacheManager).build();
NOTE: it should be noted that Memcache DOES NOT guarantee cache
coherency. It is strongly recommended that you do not use Memcache as your clustered caching solution (memcache
is fine for caching files, etc, but not data that is expected to be coherent across multiple cluster nodes).
Disable Caching
While production applications will usually enable a working CacheManager as described above, you might wish to disable caching
entirely when testing or debugging to remove 'moving parts' for better clarity into request/response
behavior. You can do this by configuring a disabled
CacheManager instance. For example:
Client client =
com.okta.sdk.client.Clients.builder().setCacheManager(
Caches.newDisabledCacheManager()
).build();
Single Instance
Finally, it should be noted that, after building a
client instance, that same instance should be used
everywhere in your application. Creating multiple client instances in a single application could have
negative side effects:
As mentioned above, a client has a
#setCacheManager(com.okta.sdk.cache.CacheManager)reference. If your application uses multiple client instances, each client's referenced CacheManager would likely
become out of sync with the others, making your cache
incoherent. This will likely
result in exposing stale data to your application and could data errors.
If you must have multiple
Client instances in your application, you should ensure that each client
references the same exact
CacheManager instance to guarantee cache coherency.