okta changedmanage-claude/wif-providers/okta
Nearest release: v2.1.302, published 12 hours after this site recorded the change. Shown because the two are within 24 hours of each other. Nothing here says the release caused the edit.
Recorded here
Lines+96added
Lines−61removed
From line
267
where the diff opens
First seen
14 Aug 2026
this site's first read of the page
Recorded edits11to this page, all time
The whole hunk
from line 267, old and new numbered
/
from line 267
267267 ```
268268
269269 ```java Java
270 IdentityTokenProvider fetchOktaToken = () -> {
271 try {
272 var form = Map.of(
273 "grant_type", "client_credentials",
274 "scope", "anthropic.access",
275 "client_assertion_type", "urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
276 // Build the RFC 7523 client_assertion JWT signed with your Okta app's private key
277 "client_assertion", buildSignedClientAssertion())
278 .entrySet().stream()
279 .map(entry -> entry.getKey() + "=" + URLEncoder.encode(entry.getValue(), UTF_8))
280 .collect(Collectors.joining("&"));
281 var request = HttpRequest.newBuilder(URI.create(System.getenv("OKTA_ISSUER") + "/v1/token"))
282 .header("content-type", "application/x-www-form-urlencoded")
283 .POST(HttpRequest.BodyPublishers.ofString(form))
284 .build();
285 var response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString());
286 return new ObjectMapper().readTree(response.body()).get("access_token").asText();
287 } catch (Exception e) {
288 throw new RuntimeException(e);
289 }
290 };
270 import com.anthropic.config.AuthenticationConfig;
271 import com.anthropic.config.AuthenticationType;
272 import com.anthropic.config.IdentityTokenConfig;
273 import com.anthropic.config.InMemoryProfileConfigProvider;
274 import com.anthropic.config.ProfileConfig;
275 // ...
276 import com.fasterxml.jackson.databind.ObjectMapper;
277 import java.net.URI;
278 import java.net.URLEncoder;
279 import java.net.http.HttpClient;
280 import java.net.http.HttpRequest;
281 import java.net.http.HttpResponse;
282 import java.util.Map;
283 import java.util.stream.Collectors;
284 import static java.nio.charset.StandardCharsets.UTF_8;
291285
292 AnthropicClient client = AnthropicOkHttpClient.builder()
293 .federationTokenProvider(
294 fetchOktaToken,
295 System.getenv("ANTHROPIC_FEDERATION_RULE_ID"),
296 System.getenv("ANTHROPIC_ORGANIZATION_ID"),
297 System.getenv("ANTHROPIC_SERVICE_ACCOUNT_ID"))
298 .build();
286 void main() throws Exception {
287 var form = Map.of(
288 "grant_type", "client_credentials",
289 "scope", "anthropic.access",
290 "client_assertion_type", "urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
291 // Build the RFC 7523 client_assertion JWT signed with your Okta app's private key
292 "client_assertion", buildSignedClientAssertion())
293 .entrySet().stream()
294 .map(entry -> entry.getKey() + "=" + URLEncoder.encode(entry.getValue(), UTF_8))
295 .collect(Collectors.joining("&"));
296 var request = HttpRequest.newBuilder(URI.create(System.getenv("OKTA_ISSUER") + "/v1/token"))
297 .header("content-type", "application/x-www-form-urlencoded")
298 .POST(HttpRequest.BodyPublishers.ofString(form))
299 .build();
299300
300 var message = client.messages().create(MessageCreateParams.builder()
301 .model(Model.CLAUDE_OPUS_5_5)
302 .maxTokens(1024)
303 .addUserMessage("Hello, Claude")
304 .build());
301 // The Java SDK takes the token itself or a file path, not a function; with
302 // source("value"), path(...) holds the token. The SDK sends that same token
303 // at every refresh of the Anthropic access token, which fails once it has
304 // expired or, if it has a jti claim, been used. For a longer-running
305 // process, pass source("file") and write a new token to the file before
306 // each refresh.
307 var response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString());
308 String oktaToken = new ObjectMapper().readTree(response.body()).get("access_token").asText();
305309
306 IO.println(message.content());
310 AnthropicClient client = AnthropicOkHttpClient.builder()
311 .configurationProvider(InMemoryProfileConfigProvider.of(ProfileConfig.builder()
312 .organizationId(System.getenv("ANTHROPIC_ORGANIZATION_ID"))
313 .workspaceId(System.getenv("ANTHROPIC_WORKSPACE_ID"))
314 .authentication(AuthenticationConfig.builder()
315 .type(AuthenticationType.OIDC_FEDERATION)
316 .federationRuleId(System.getenv("ANTHROPIC_FEDERATION_RULE_ID"))
317 .serviceAccountId(System.getenv("ANTHROPIC_SERVICE_ACCOUNT_ID"))
318 .identityToken(IdentityTokenConfig.builder()
319 .source("value")
320 .path(oktaToken)
321 .build())
322 .build())
323 .build()))
324 .build();
325
326 var message = client.messages().create(MessageCreateParams.builder()
327 .model(Model.CLAUDE_OPUS_5_5)
328 .maxTokens(1024)
329 .addUserMessage("Hello, Claude")
330 .build());
331
332 IO.println(message.content());
333 }
307334 ```
308335
309336 ```csharp C#
from line 407
380407
381408 ```php PHP
382409 use Anthropic\Client;
383 use Anthropic\Credentials\WorkloadIdentityCredentials;
410 use Anthropic\Lib\Credentials\CredentialResult;
411 use Anthropic\Lib\Credentials\IdentityTokenProvider;
412 use Anthropic\Lib\Credentials\TokenCache;
413 use Anthropic\Lib\Credentials\WorkloadIdentityCredentials;
384414
385 function fetchOktaToken(): string
415 class OktaIdentityToken implements IdentityTokenProvider
386416 {
387 $ch = curl_init(getenv('OKTA_ISSUER') . '/v1/token');
388 curl_setopt_array($ch, [
389 CURLOPT_RETURNTRANSFER => true,
390 CURLOPT_POSTFIELDS => http_build_query([
391 'grant_type' => 'client_credentials',
392 'scope' => 'anthropic.access',
393 'client_assertion_type' => 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer',
394 // Build the RFC 7523 client_assertion JWT signed with your Okta app's private key
395 'client_assertion' => buildSignedClientAssertion(),
396 ]),
397 ]);
398 $body = json_decode(curl_exec($ch), true);
399 curl_close($ch);
400 return $body['access_token'];
417 public function getIdentityToken(): string
418 {
419 $ch = curl_init(getenv('OKTA_ISSUER') . '/v1/token');
420 curl_setopt_array($ch, [
421 CURLOPT_RETURNTRANSFER => true,
422 CURLOPT_POSTFIELDS => http_build_query([
423 'grant_type' => 'client_credentials',
424 'scope' => 'anthropic.access',
425 'client_assertion_type' => 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer',
426 // Build the RFC 7523 client_assertion JWT signed with your Okta app's private key
427 'client_assertion' => buildSignedClientAssertion(),
428 ]),
429 ]);
430 $body = json_decode(curl_exec($ch), true);
431 curl_close($ch);
432 return $body['access_token'];
433 }
401434 }
402435
403436 $client = new Client(
404 credentials: new WorkloadIdentityCredentials(
405 identityTokenProvider: fetchOktaToken(...),
406 federationRuleId: getenv('ANTHROPIC_FEDERATION_RULE_ID'),
407 organizationId: getenv('ANTHROPIC_ORGANIZATION_ID'),
408 serviceAccountId: getenv('ANTHROPIC_SERVICE_ACCOUNT_ID'),
409 workspaceId: getenv('ANTHROPIC_WORKSPACE_ID') ?: null,
437 credentials: new CredentialResult(
438 provider: new TokenCache(new WorkloadIdentityCredentials(
439 identityProvider: new OktaIdentityToken(),
440 federationRuleId: getenv('ANTHROPIC_FEDERATION_RULE_ID'),
441 organizationId: getenv('ANTHROPIC_ORGANIZATION_ID'),
442 serviceAccountId: getenv('ANTHROPIC_SERVICE_ACCOUNT_ID'),
443 workspaceId: getenv('ANTHROPIC_WORKSPACE_ID') ?: null,
444 )),
410445 ),
411446 );
412447
from line 490
455490 ```
456491</CodeGroup>
457492
458Each SDK tab shows the callable pattern: the Anthropic SDK calls the function you passed to `identity_token_provider` (typescript, php: `identityTokenProvider`; csharp: `IdentityTokenProvider`; go: `option.WithFederationTokenProvider`; java: `federationTokenProvider`) each time the Anthropic access token approaches expiry, so your Okta fetcher should return a fresh token on each call rather than caching one indefinitely. The `ant` CLI re-reads `ANTHROPIC_IDENTITY_TOKEN_FILE` on each exchange, so refresh that file on a timer for long-running shells.
493Except in Java (see the comment in that example), the SDK example passes your Okta token fetch to `identity_token_provider` (typescript: `identityTokenProvider`; php: `identityProvider`; csharp: `IdentityTokenProvider`; go: `option.WithFederationTokenProvider`; java: `IdentityTokenConfig`) as a token provider. The Claude SDK calls it each time the Anthropic access token approaches expiry, so your Okta fetcher should return a fresh token on each call rather than caching one indefinitely. The `ant` CLI re-reads `ANTHROPIC_IDENTITY_TOKEN_FILE` on each exchange, so refresh that file on a timer for long-running shells.
459494
460495## Verify the setup
461496
No line in this hunk matches that.