Core API
Core services are obtained via ServiceLocator and designed to be testable and mockable. Prefer requesting services once and reusing them.
ServiceLocator
tryGetService(clazz)/getService(clazz): looks up core services.
getAuthManager(accountClass, displayName, pluginAuthInterface): creates OAuth2-compatible managers for your accounts.
Check the following Kotlin example:
val settings = serviceLocator.getService<PluginSettingsStore>()
val secrets = serviceLocator.getService<PluginSecretStoreSuspending>()
val logger = serviceLocator.getService<Logger>()
Settings and Secrets
PluginSettingsStore: per-plugin key-value store (simple MutableMap<String, String>)
PluginSecretStoreSuspending: suspendable secrets store for sensitive data. We suggest using this one instead of deprecated PluginSecretStore.
Check the following Kotlin example:
settings["lastEnvironmentId"] = env.id
val token = secrets["accessToken"] ?: run {
// trigger login
null
}
Authentication
Use ServiceLocator.getAuthManager to create PluginAuthManager<A, LoginConfiguration> by providing PluginAuthInterface:
data class MyAccount(val id: String, val displayName: String) : Account
data class MyLoginCfg(val tenant: String)
class MyAuthInterface : PluginAuthInterface<MyAccount, MyLoginCfg> {
override fun serialize(account: MyAccount) = account.id
override fun deserialize(string: String) = MyAccount(string, string)
override suspend fun createAccount(token: OAuthToken, config: AuthConfiguration) =
MyAccount(token.accessToken.take(8), "User")
override suspend fun updateAccount(token: OAuthToken, account: MyAccount) = account
override fun createAuthConfig(loginConfiguration: MyLoginCfg) =
AuthConfiguration(
authUrl = URI("https://auth.example.com/oauth/authorize"),
tokenUrl = URI("https://auth.example.com/oauth/token"),
clientId = "client-id",
scope = "openid profile"
)
override fun createRefreshConfig(account: MyAccount) = RefreshConfiguration(
tokenUrl = URI("https://auth.example.com/oauth/token"), clientId = "client-id"
)
}
val auth = serviceLocator.getAuthManager<MyAccount, MyLoginCfg>(
displayName = "ExampleAuth",
pluginAuthInterface = MyAuthInterface()
)
// Start login
val url = auth.initiateLogin(MyLoginCfg(tenant = "prod"))
// Open in browser and later handle the redirect in handleUri
Use the following best practices:
getToken(accountId, forceRefresh) is suspending and may throw NetworkException or LoginException. Use the UI to handle and surface such errors.
Listen to events: SharedFlow<AuthEvent> to react to the login or logout changes and update your environments.
The redirectUrl is managed by the Toolbox App automatically. Do not set it manually since the Toolbox App replaces it with its predefined value.
27 October 2025