Authenticate with Kessel SDKs
All Kessel SDKs support the OAuth 2.0 Client Credentials grant for service-to-service authentication. The SDK handles token caching and automatic refresh transparently.
Install Authentication Dependencies
Section titled âInstall Authentication DependenciesâSome SDKs require an optional dependency to use authentication features:
| SDK | Installation |
|---|---|
| Python | pip install "kessel-sdk[auth]" |
| Ruby | Add gem 'openid_connect' to your Gemfile |
| Java | Include the Nimbus OAuth SDK (com.nimbusds:oauth2-oidc-sdk) |
| Go, TypeScript | Included in the core package |
Configure Credentials
Section titled âConfigure CredentialsâOption 1: OIDC Discovery (Recommended)
Section titled âOption 1: OIDC Discovery (Recommended)âUse OIDC Discovery when your OAuth provider publishes a .well-known/openid-configuration endpoint. The SDK fetches the token endpoint URL for you.
# Option 1: Use OIDC discovery to find the token endpoint automaticallydiscovery = fetch_oidc_discovery(os.getenv("ISSUER_URL"))credentials = OAuth2ClientCredentials( client_id=os.getenv("CLIENT_ID"), client_secret=os.getenv("CLIENT_SECRET"), token_endpoint=discovery.token_endpoint,)// Option 1: Use OIDC discovery to find the token endpoint automaticallydiscovered, err := auth.FetchOIDCDiscovery(ctx, os.Getenv("ISSUER_URL"), auth.FetchOIDCDiscoveryOptions{})if err != nil { log.Fatal("OIDC discovery failed:", err)}credentials := auth.NewOAuth2ClientCredentials( os.Getenv("CLIENT_ID"), os.Getenv("CLIENT_SECRET"), discovered.TokenEndpoint,)// Option 1: Use OIDC discovery to find the token endpoint automaticallyconst discovery = await fetchOIDCDiscovery(process.env.ISSUER_URL!);let credentials = new OAuth2ClientCredentials({ clientId: process.env.CLIENT_ID!, clientSecret: process.env.CLIENT_SECRET!, tokenEndpoint: discovery.tokenEndpoint,});# Option 1: Use OIDC discovery to find the token endpoint automaticallydiscovery = fetch_oidc_discovery(ENV.fetch('ISSUER_URL'))credentials = OAuth2ClientCredentials.new( client_id: ENV.fetch('CLIENT_ID'), client_secret: ENV.fetch('CLIENT_SECRET'), token_endpoint: discovery.token_endpoint,)// Option 1: Use OIDC discovery to find the token endpoint automaticallyOIDCDiscoveryMetadata discovery = OIDCDiscovery.fetchOIDCDiscovery(issuerUrl);OAuth2ClientCredentials credentials = new OAuth2ClientCredentials( new ClientConfigAuth(clientId, clientSecret, discovery.tokenEndpoint()));Option 2: Direct Token URL
Section titled âOption 2: Direct Token URLâUse a direct token URL when your OAuth provider does not support OIDC Discovery, or when you want explicit control over the token endpoint.
# Option 2: Provide the token endpoint URL directlycredentials = OAuth2ClientCredentials( client_id=os.getenv("CLIENT_ID"), client_secret=os.getenv("CLIENT_SECRET"), token_endpoint=os.getenv("TOKEN_ENDPOINT"),)// Option 2: Provide the token endpoint URL directlycredentials = auth.NewOAuth2ClientCredentials( os.Getenv("CLIENT_ID"), os.Getenv("CLIENT_SECRET"), os.Getenv("TOKEN_ENDPOINT"),)// Option 2: Provide the token endpoint URL directlycredentials = new OAuth2ClientCredentials({ clientId: process.env.CLIENT_ID!, clientSecret: process.env.CLIENT_SECRET!, tokenEndpoint: process.env.TOKEN_ENDPOINT!,});# Option 2: Provide the token endpoint URL directlycredentials = OAuth2ClientCredentials.new( client_id: ENV.fetch('CLIENT_ID'), client_secret: ENV.fetch('CLIENT_SECRET'), token_endpoint: ENV.fetch('TOKEN_ENDPOINT'),)// Option 2: Provide the token endpoint URL directlyString tokenEndpoint = System.getenv("TOKEN_ENDPOINT");credentials = new OAuth2ClientCredentials( new ClientConfigAuth(clientId, clientSecret, tokenEndpoint));Using Credentials
Section titled âUsing CredentialsâThe same OAuth2ClientCredentials object works with both services, but is wrapped differently depending on the protocol.
With Inventory API (gRPC)
Section titled âWith Inventory API (gRPC)âPass credentials to the ClientBuilder to build an authenticated gRPC client.
stub, channel = ( ClientBuilder(os.getenv("KESSEL_ENDPOINT")) .oauth2_client_authenticated(credentials) .build())client, conn, err := v1beta2.NewClientBuilder(os.Getenv("KESSEL_ENDPOINT")). OAuth2ClientAuthenticated(&credentials, nil). Build()if err != nil { log.Fatal("Failed to create client:", err)}defer conn.Close()const client = new ClientBuilder(process.env.KESSEL_ENDPOINT!) .oauth2ClientAuthenticated(credentials) .buildAsync();client = Kessel::Inventory::V1beta2::KesselInventoryService::ClientBuilder .new(ENV.fetch('KESSEL_ENDPOINT')) .oauth2_client_authenticated(oauth2_client_credentials: credentials) .buildPair<KesselInventoryServiceBlockingStub, ManagedChannel> clientAndChannel = new ClientBuilder(kesselEndpoint) .oauth2ClientAuthenticated(credentials) .build();KesselInventoryServiceBlockingStub client = clientAndChannel.getLeft();ManagedChannel channel = clientAndChannel.getRight();With RBAC Helpers (HTTP)
Section titled âWith RBAC Helpers (HTTP)âRBAC REST helpers like fetchRootWorkspace accept an AuthRequest object that injects the Bearer token into each HTTP request. Use oauth2AuthRequest to create one from your credentials.
# Wrap credentials as an HTTP auth adapter for RBAC REST callsauth = oauth2_auth_request(credentials)
root_workspace = fetch_root_workspace( rbac_base_endpoint=os.getenv("RBAC_ENDPOINT"), org_id=os.getenv("ORG_ID"), auth=auth,)print(f"Root workspace: {root_workspace.name} (ID: {root_workspace.id})")// Wrap credentials as an HTTP auth adapter for RBAC REST callsauthRequest := auth.OAuth2AuthRequest(&credentials, auth.OAuth2AuthRequestOptions{})
rootWorkspace, err := v2.FetchRootWorkspace(ctx, os.Getenv("RBAC_ENDPOINT"), os.Getenv("ORG_ID"), v2.FetchWorkspaceOptions{ Auth: authRequest,})if err != nil { log.Fatal("Failed to fetch workspace:", err)}log.Printf("Root workspace: %s (ID: %s)", rootWorkspace.Name, rootWorkspace.Id)// Wrap credentials as an HTTP auth adapter for RBAC REST callsconst auth = oauth2AuthRequest(credentials);
const rootWorkspace = await fetchRootWorkspace( process.env.RBAC_ENDPOINT!, process.env.ORG_ID!, auth,);console.log(`Root workspace: ${rootWorkspace.name} (ID: ${rootWorkspace.id})`);# Wrap credentials as an HTTP auth adapter for RBAC REST callsauth = oauth2_auth_request(credentials)
root_workspace = fetch_root_workspace( ENV.fetch('RBAC_ENDPOINT'), ENV.fetch('ORG_ID'), auth: auth,)puts "Root workspace: #{root_workspace.name} (ID: #{root_workspace.id})"// Wrap credentials as an HTTP auth adapter for RBAC REST callsOAuth2AuthRequest auth = new OAuth2AuthRequest(credentials);
Workspace rootWorkspace = FetchWorkspace.fetchRootWorkspace( System.getenv("RBAC_ENDPOINT"), System.getenv("ORG_ID"), auth);System.out.println("Root workspace: " + rootWorkspace.getName() + " (ID: " + rootWorkspace.getId() + ")");Token Management
Section titled âToken ManagementâThe SDK handles token lifecycle automatically:
- Token caching: tokens are reused until they approach expiration (within 5 minutes of expiry)
- Automatic refresh: a new token is fetched before the cached one expires
- Concurrency safe: concurrent requests share a single in-flight token fetch rather than each triggering a refresh
Complete Example
Section titled âComplete Exampleâimport osfrom kessel.auth import OAuth2ClientCredentials, fetch_oidc_discovery, oauth2_auth_requestfrom kessel.inventory.v1beta2 import ClientBuilderfrom kessel.rbac.v2 import fetch_root_workspace
def main(): # Option 1: Use OIDC discovery to find the token endpoint automatically discovery = fetch_oidc_discovery(os.getenv("ISSUER_URL")) credentials = OAuth2ClientCredentials( client_id=os.getenv("CLIENT_ID"), client_secret=os.getenv("CLIENT_SECRET"), token_endpoint=discovery.token_endpoint, )
# Option 2: Provide the token endpoint URL directly credentials = OAuth2ClientCredentials( client_id=os.getenv("CLIENT_ID"), client_secret=os.getenv("CLIENT_SECRET"), token_endpoint=os.getenv("TOKEN_ENDPOINT"), )
stub, channel = ( ClientBuilder(os.getenv("KESSEL_ENDPOINT")) .oauth2_client_authenticated(credentials) .build() )
channel.close()
# Wrap credentials as an HTTP auth adapter for RBAC REST calls auth = oauth2_auth_request(credentials)
root_workspace = fetch_root_workspace( rbac_base_endpoint=os.getenv("RBAC_ENDPOINT"), org_id=os.getenv("ORG_ID"), auth=auth, ) print(f"Root workspace: {root_workspace.name} (ID: {root_workspace.id})")
if __name__ == "__main__": main()package main
import ( "context" "log" "os"
"github.com/project-kessel/kessel-sdk-go/kessel/auth" "github.com/project-kessel/kessel-sdk-go/kessel/inventory/v1beta2" v2 "github.com/project-kessel/kessel-sdk-go/kessel/rbac/v2")
func main() { ctx := context.Background()
// Option 1: Use OIDC discovery to find the token endpoint automatically discovered, err := auth.FetchOIDCDiscovery(ctx, os.Getenv("ISSUER_URL"), auth.FetchOIDCDiscoveryOptions{}) if err != nil { log.Fatal("OIDC discovery failed:", err) } credentials := auth.NewOAuth2ClientCredentials( os.Getenv("CLIENT_ID"), os.Getenv("CLIENT_SECRET"), discovered.TokenEndpoint, )
// Option 2: Provide the token endpoint URL directly credentials = auth.NewOAuth2ClientCredentials( os.Getenv("CLIENT_ID"), os.Getenv("CLIENT_SECRET"), os.Getenv("TOKEN_ENDPOINT"), )
client, conn, err := v1beta2.NewClientBuilder(os.Getenv("KESSEL_ENDPOINT")). OAuth2ClientAuthenticated(&credentials, nil). Build() if err != nil { log.Fatal("Failed to create client:", err) } defer conn.Close()
_ = client
// Wrap credentials as an HTTP auth adapter for RBAC REST calls authRequest := auth.OAuth2AuthRequest(&credentials, auth.OAuth2AuthRequestOptions{})
rootWorkspace, err := v2.FetchRootWorkspace(ctx, os.Getenv("RBAC_ENDPOINT"), os.Getenv("ORG_ID"), v2.FetchWorkspaceOptions{ Auth: authRequest, }) if err != nil { log.Fatal("Failed to fetch workspace:", err) } log.Printf("Root workspace: %s (ID: %s)", rootWorkspace.Name, rootWorkspace.Id)}import { ClientBuilder } from "@project-kessel/kessel-sdk/kessel/inventory/v1beta2";import { fetchOIDCDiscovery, OAuth2ClientCredentials, oauth2AuthRequest,} from "@project-kessel/kessel-sdk/kessel/auth";import { fetchRootWorkspace } from "@project-kessel/kessel-sdk/kessel/rbac/v2";
async function main() { // Option 1: Use OIDC discovery to find the token endpoint automatically const discovery = await fetchOIDCDiscovery(process.env.ISSUER_URL!); let credentials = new OAuth2ClientCredentials({ clientId: process.env.CLIENT_ID!, clientSecret: process.env.CLIENT_SECRET!, tokenEndpoint: discovery.tokenEndpoint, });
// Option 2: Provide the token endpoint URL directly credentials = new OAuth2ClientCredentials({ clientId: process.env.CLIENT_ID!, clientSecret: process.env.CLIENT_SECRET!, tokenEndpoint: process.env.TOKEN_ENDPOINT!, });
const client = new ClientBuilder(process.env.KESSEL_ENDPOINT!) .oauth2ClientAuthenticated(credentials) .buildAsync();
void client;
// Wrap credentials as an HTTP auth adapter for RBAC REST calls const auth = oauth2AuthRequest(credentials);
const rootWorkspace = await fetchRootWorkspace( process.env.RBAC_ENDPOINT!, process.env.ORG_ID!, auth, ); console.log(`Root workspace: ${rootWorkspace.name} (ID: ${rootWorkspace.id})`);}
main();#!/usr/bin/env ruby# frozen_string_literal: true
require 'kessel-sdk'
include Kessel::Authinclude Kessel::RBAC::V2
# Option 1: Use OIDC discovery to find the token endpoint automaticallydiscovery = fetch_oidc_discovery(ENV.fetch('ISSUER_URL'))credentials = OAuth2ClientCredentials.new( client_id: ENV.fetch('CLIENT_ID'), client_secret: ENV.fetch('CLIENT_SECRET'), token_endpoint: discovery.token_endpoint,)
# Option 2: Provide the token endpoint URL directlycredentials = OAuth2ClientCredentials.new( client_id: ENV.fetch('CLIENT_ID'), client_secret: ENV.fetch('CLIENT_SECRET'), token_endpoint: ENV.fetch('TOKEN_ENDPOINT'),)
client = Kessel::Inventory::V1beta2::KesselInventoryService::ClientBuilder .new(ENV.fetch('KESSEL_ENDPOINT')) .oauth2_client_authenticated(oauth2_client_credentials: credentials) .build
# Wrap credentials as an HTTP auth adapter for RBAC REST callsauth = oauth2_auth_request(credentials)
root_workspace = fetch_root_workspace( ENV.fetch('RBAC_ENDPOINT'), ENV.fetch('ORG_ID'), auth: auth,)puts "Root workspace: #{root_workspace.name} (ID: #{root_workspace.id})"package org.project_kessel.examples;
import com.nimbusds.jose.util.Pair;import io.grpc.ManagedChannel;import org.project_kessel.api.auth.ClientConfigAuth;import org.project_kessel.api.auth.OAuth2AuthRequest;import org.project_kessel.api.auth.OAuth2ClientCredentials;import org.project_kessel.api.auth.OIDCDiscovery;import org.project_kessel.api.auth.OIDCDiscoveryMetadata;import org.project_kessel.api.inventory.v1beta2.ClientBuilder;import org.project_kessel.api.inventory.v1beta2.KesselInventoryServiceGrpc.KesselInventoryServiceBlockingStub;import org.project_kessel.api.rbac.v2.FetchWorkspace;import org.project_kessel.api.rbac.v2.Workspace;
public class AuthExample {
public static void main(String[] args) { String issuerUrl = System.getenv("ISSUER_URL"); String clientId = System.getenv("CLIENT_ID"); String clientSecret = System.getenv("CLIENT_SECRET"); String kesselEndpoint = System.getenv("KESSEL_ENDPOINT");
// Option 1: Use OIDC discovery to find the token endpoint automatically OIDCDiscoveryMetadata discovery = OIDCDiscovery.fetchOIDCDiscovery(issuerUrl); OAuth2ClientCredentials credentials = new OAuth2ClientCredentials( new ClientConfigAuth(clientId, clientSecret, discovery.tokenEndpoint()));
// Option 2: Provide the token endpoint URL directly String tokenEndpoint = System.getenv("TOKEN_ENDPOINT"); credentials = new OAuth2ClientCredentials( new ClientConfigAuth(clientId, clientSecret, tokenEndpoint));
Pair<KesselInventoryServiceBlockingStub, ManagedChannel> clientAndChannel = new ClientBuilder(kesselEndpoint) .oauth2ClientAuthenticated(credentials) .build(); KesselInventoryServiceBlockingStub client = clientAndChannel.getLeft(); ManagedChannel channel = clientAndChannel.getRight();
channel.shutdown();
// Wrap credentials as an HTTP auth adapter for RBAC REST calls OAuth2AuthRequest auth = new OAuth2AuthRequest(credentials);
Workspace rootWorkspace = FetchWorkspace.fetchRootWorkspace( System.getenv("RBAC_ENDPOINT"), System.getenv("ORG_ID"), auth); System.out.println("Root workspace: " + rootWorkspace.getName() + " (ID: " + rootWorkspace.getId() + ")"); }}Related Documentation
Section titled âRelated Documentationâ- Client SDK Specification â for SDK developers
- API Reference: auth package â detailed API documentation