Class ApiKeyCredential

java.lang.Object
io.superdurable.dex.ApiKeyCredential
All Implemented Interfaces:
Credential, AutoCloseable

public final class ApiKeyCredential extends Object implements AutoCloseable
Exchanges a long-lived API key for short-lived Dex bearer tokens.

Use this credential when the application holds an API key and Dex accepts access tokens. Use FileCredential when another process writes an access token to a local file. The first call exchanges the key; concurrent callers share that exchange. A token call after 80% of its lifetime starts one background exchange while callers continue using the valid token. A failed refresh is retried no more often than every five seconds while that token remains valid. An expired token makes callers wait for the shared exchange, up to the configured timeout. Dex rejection discards only the rejected token, and unary service calls retry once with a fresh one.

The token endpoint must use HTTPS, except that HTTP is allowed for localhost, 127.0.0.0/8, and ::1. Redirect responses fail without forwarding the API key. A gRPC call deadline or cancellation bounds a waiting token lookup. This class is thread-safe. The application owns and closes it after all Clients and Workers sharing it are closed. A supplied HTTP connection factory remains caller-owned. The credential description contains no secrets. Exchange errors redact the API key, cached and two most recently issued access tokens, the failed response's access token, and JWT-shaped substrings before truncating each endpoint error field to 200 characters. A JWT-shaped substring has three or more base64url segments of at least 10 characters each. The rule also applies to the token URL and can redact other text of that shape, such as a long dotted host name. Raw transport causes are omitted.

ApiKeyCredential credential = ApiKeyCredential.builder(
        URI.create("https://auth.example.com/token"), "dex-server-id", apiKey).build();
try (ApiKeyCredential ownedCredential = credential;
        Client client = new Client(registry, blobCache,
        ClientOptions.newBuilder().serverAddress("dex.example.com:8801")
                .credential(ownedCredential).build())) {
    client.searchFlows("", 10);
}
  • Method Details

    • builder

      public static ApiKeyCredential.Builder builder(URI tokenUrl, String serverId, String apiKey)
      Begins configuring an API key exchange without contacting the token endpoint.
      Parameters:
      tokenUrl - the absolute token endpoint URL, using HTTPS or loopback HTTP
      serverId - the exact Dex server ID used to scope the access token
      apiKey - the nonempty long-lived API key
      Returns:
      a builder with a ten-second exchange timeout
      Throws:
      IllegalArgumentException - if any input is absent or the URL violates the transport rule
    • token

      Returns a cached access token or waits for one exchange when no valid token exists.

      The first call and expired-token calls wait no longer than the exchange timeout. Concurrent callers share one exchange. Valid tokens return immediately while a refresh runs.

      Specified by:
      token in interface Credential
      Returns:
      a nonempty access token without the Bearer prefix
      Throws:
      ApiKeyCredential.ExchangeException - if the endpoint, response, transport, or exchange deadline fails
      InterruptedException - if the waiting caller is interrupted
      IllegalStateException - if the credential has been closed
    • rejectToken

      public void rejectToken(String token)
      Discards a rejected access token only when it is still cached.

      The SDK invokes this after Dex rejects an authenticated call. An older rejected token leaves a newer cached token intact. This method is safe for concurrent calls.

      Parameters:
      token - the exact access token rejected by Dex, or null to do nothing
    • close

      public void close()
      Cancels an exchange and interrupts its daemon thread.

      The application closes this credential after every Client and Worker sharing it has closed. Closing it earlier causes later token calls to fail. Closing is safe more than once.

      Specified by:
      close in interface AutoCloseable
    • toString

      public String toString()
      Describes this credential without revealing either secret.
      Overrides:
      toString in class Object
      Returns:
      a fixed redacted description