Skip to content

fix: KeyError: 'token' in PrivateKey Authentication Mode#510

Open
agburch wants to merge 1 commit intookta:masterfrom
agburch:gillen/fix-missing-key-error
Open

fix: KeyError: 'token' in PrivateKey Authentication Mode#510
agburch wants to merge 1 commit intookta:masterfrom
agburch:gillen/fix-missing-key-error

Conversation

@agburch
Copy link
Contributor

@agburch agburch commented Mar 11, 2026

Fix KeyError: 'token' in PrivateKey Authentication Mode

Summary

This PR fixes a critical bug that prevents the Okta SDK from initializing when using PrivateKey (OAuth 2.0) authentication mode. The issue causes a KeyError: 'token' exception during client initialization, making it impossible to use the OAuth 2.0 client credentials flow.

Issue Fixed

KeyError: 'token' in ApiClient initialization

File: okta/api_client.py (line 91)

Problem:
When using authorizationMode: 'PrivateKey', the SDK crashes during client initialization because it tries to access a required token field that doesn't exist in the configuration.

# Before (crashes)
access_token=configuration["client"]["token"],

# After (works)
access_token=configuration["client"].get("token", None),

Root Cause:
PrivateKey authentication mode uses a private key to dynamically generate OAuth tokens via the client credentials flow. No pre-existing token is needed or expected in the configuration. The code incorrectly assumed a token field would always be present, regardless of authentication mode.

Impact:

  • Any application using PrivateKey authentication mode fails immediately with KeyError: 'token' during client initialization
  • This completely blocks OAuth 2.0 client credentials flow implementations
  • Users cannot authenticate using service accounts with private keys

Error Stack Trace

Traceback (most recent call last):
  File "script.py", line 70, in <module>
    okta_client = OktaClient(OKTA_CONFIG)
  File "/usr/local/lib/python3.14/site-packages/okta/client.py", line 52, in __init__
    super().__init__(configuration=configuration)
  File "/usr/local/lib/python3.14/site-packages/okta/api_client.py", line 91, in __init__
    access_token=configuration["client"]["token"],
                 ~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^
KeyError: 'token'

Testing

Before Fix

OKTA_CONFIG = {
    'authorizationMode': 'PrivateKey',
    'clientId': '0oaxxxxxxxxxxxxx',
    'scopes': ['okta.groups.manage', 'okta.groups.read', 'okta.users.read'],
    'privateKey': '-----BEGIN PRIVATE KEY-----\n...',
    'orgUrl': 'https://example.okta.com',
}

okta_client = OktaClient(OKTA_CONFIG)  # ❌ KeyError: 'token'

After Fix

# Same configuration now works
okta_client = OktaClient(OKTA_CONFIG)  # ✅ Initializes successfully
result = await okta_client.list_group_users(group_id)  # ✅ OAuth token generated and API call succeeds

Configuration Examples

PrivateKey Authentication (OAuth 2.0) - Now Works

config = {
    'authorizationMode': 'PrivateKey',
    'clientId': 'your-client-id',
    'scopes': ['okta.users.read', 'okta.groups.read'],
    'privateKey': '-----BEGIN PRIVATE KEY-----\n...',
    'orgUrl': 'https://your-domain.okta.com',
}

SSWS Authentication (API Token) - Continues to Work

config = {
    'authorizationMode': 'SSWS',
    'token': 'your-api-token',
    'orgUrl': 'https://your-domain.okta.com',
}

Both authentication modes now work correctly.

How Authentication Modes Work

The SDK supports two authentication modes:

  1. SSWS (API Token): Uses token field directly for authentication
  2. PrivateKey (OAuth 2.0): Uses privateKey to dynamically generate OAuth tokens

The fix ensures that:

  • When authorizationMode is "PrivateKey", no token is required (uses privateKey instead)
  • When authorizationMode is "SSWS", the token field is still used as before
  • The Configuration class properly handles access_token=None for PrivateKey mode

Code Review Notes

Why .get() with None is safe:

Looking at okta/configuration.py, the Configuration class already handles access_token=None:

def __init__(self, ..., access_token=None, ...):
    self.access_token = access_token  # None is acceptable

And in auth_settings():

def auth_settings(self):
    auth = {}
    # ... other auth methods ...
    if self.access_token is not None:  # Only adds oauth2 if token exists
        auth["oauth2"] = {...}
    return auth

The SDK was already designed to handle access_token=None, but api_client.py was incorrectly requiring the token field to exist in the configuration dictionary.

Related Documentation

Additional Notes

This bug likely went undetected because:

  1. Most testing focused on SSWS (API token) authentication
  2. The bug only manifests during client initialization with PrivateKey mode
  3. PR Python MGMT SDK: SDK making malformed request for OAuth access tokens in v 3.0.0 #507 fixed downstream OAuth issues, but this initialization bug prevented reaching that code

The fix uses a defensive programming practice (dict.get() with a default value) that should have been used from the start, especially since the SDK already supports multiple authentication modes.

@agburch agburch changed the title handle unset token key in config dict Handle KeyError: 'token' in PrivateKey Authentication Mode Mar 11, 2026
@agburch agburch changed the title Handle KeyError: 'token' in PrivateKey Authentication Mode fix: KeyError: 'token' in PrivateKey Authentication Mode Mar 11, 2026
@agburch
Copy link
Contributor Author

agburch commented Mar 11, 2026

@BinoyOza-okta - could you take a look at this? Seems like a trivial fix, but this issue popped up recently (since v3.0.0) and broke some of our pipelines

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant