Auth¶
auth ¶
Solution-wide authentication infrastructure.
This module provides authentication functionality including: - Token management (refresh and access tokens) - Keycloak integration for token refresh - Keyring storage for secure token persistence - JWT validation and parsing - Authentication handler that orchestrates all auth operations - CLI command for managing authentication tokens
ApiKeyNotFoundError ¶
Bases: NexusError
Raised when no authentication api key is found.
Source code in src/miura/auth/exceptions.py
_redact_sensitive_data ¶
Redact sensitive information from details dictionary.
Source code in src/miura/sdk/exceptions.py
__init__ ¶
Initialize an ApiKeyNotFoundError.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
reason
|
Optional[str]
|
Optional custom error message |
None
|
details
|
Optional[Dict[str, Any]]
|
Optional dictionary with additional context |
None
|
Source code in src/miura/auth/exceptions.py
ApiKeyExpiredError ¶
Bases: NexusError
Raised when the authentication api key has expired.
Source code in src/miura/auth/exceptions.py
_redact_sensitive_data ¶
Redact sensitive information from details dictionary.
Source code in src/miura/sdk/exceptions.py
__init__ ¶
Initialize an ApiKeyExpiredError.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
reason
|
Optional[str]
|
Optional custom error message |
None
|
details
|
Optional[Dict[str, Any]]
|
Optional dictionary with additional context |
None
|
Source code in src/miura/auth/exceptions.py
ApiKeyInvalidError ¶
Bases: NexusError
Raised when the authentication api key is invalid or malformed.
Source code in src/miura/auth/exceptions.py
_redact_sensitive_data ¶
Redact sensitive information from details dictionary.
Source code in src/miura/sdk/exceptions.py
__init__ ¶
Initialize an ApiKeyInvalidError.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
reason
|
Optional[str]
|
Optional custom error message |
None
|
details
|
Optional[Dict[str, Any]]
|
Optional dictionary with additional context |
None
|
Source code in src/miura/auth/exceptions.py
KeyringError ¶
Bases: NexusError
Raised when there's an error accessing the system keyring.
Source code in src/miura/auth/exceptions.py
_redact_sensitive_data ¶
Redact sensitive information from details dictionary.
Source code in src/miura/sdk/exceptions.py
__init__ ¶
Initialize a KeyringError.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
reason
|
Optional[str]
|
Optional custom error message |
None
|
details
|
Optional[Dict[str, Any]]
|
Optional dictionary with additional context |
None
|
Source code in src/miura/auth/exceptions.py
AuthHandler ¶
Main authentication handler that orchestrates all auth operations.
Source code in src/miura/auth/handler.py
32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 | |
__init__ ¶
__init__(config_manager: Optional[ConfigurationManager] = None, storage_backend: Optional[str] = None, verify_ssl: Optional[bool] = None)
Initialize authentication handler.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
config_manager
|
Optional[ConfigurationManager]
|
Optional ConfigurationManager instance |
None
|
storage_backend
|
Optional[str]
|
Storage backend type ("file", "keyring", or "none"). Defaults to "file". |
None
|
verify_ssl
|
Optional[bool]
|
Whether to verify SSL certificates. If None, reads from MIURA_KEYCLOAK_VERIFY_SSL env var (default: True) |
None
|
Source code in src/miura/auth/handler.py
_get_keyring_cache ¶
Get keyring cache (read once per command execution).
Returns:
| Type | Description |
|---|---|
Dict[str, str]
|
Dictionary of cached keyring values |
Source code in src/miura/auth/handler.py
_clear_keyring_cache ¶
_sync_refresh_token_from_sources ¶
Ensure the in-memory refresh token reflects the latest value from sources.
Resolution order: 1. Environment variable (MIURA_NEXUS_API_KEY) - highest priority 2. Storage backend (file, keyring, or none) - based on --storage flag 3. Keyring (if --storage=keyring or MIURA_AUTH_STORAGE=keyring)
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
storage_backend_type
|
Optional[str]
|
Optional override for storage backend type |
None
|
Returns:
| Type | Description |
|---|---|
Optional[str]
|
Optional[str]: The current refresh token if available, otherwise None. |
Raises:
| Type | Description |
|---|---|
ApiKeyInvalidError
|
If a token from any source is malformed. |
KeyringError
|
If keyring access fails unexpectedly. |
Source code in src/miura/auth/handler.py
117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 | |
get_auth_api_key ¶
Get an access token for API authentication. Uses refresh token to fetch fresh access tokens transparently. Priority order: 1) Environment variable, 2) Memory cache, 3) Keyring.
Returns:
| Name | Type | Description |
|---|---|---|
str |
str
|
The access token for API authentication |
Raises:
| Type | Description |
|---|---|
ApiKeyNotFoundError
|
If no refresh token is found in any source |
KeyringError
|
If there's an error accessing keyring |
ApiKeyInvalidError
|
If refresh token format is invalid |
PermissionError
|
If token refresh fails |
Source code in src/miura/auth/handler.py
set_auth_api_key ¶
Store a refresh token (presented as API key to user) in storage backend.
When storing in a specific backend, clears tokens from other backends to maintain a single source of truth.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
api_key
|
str
|
The refresh token to store (user sees this as API key) |
required |
Raises:
| Type | Description |
|---|---|
ApiKeyInvalidError
|
If refresh token format is invalid |
KeyringError
|
If there's an error storing in keyring (when using keyring backend) |
Source code in src/miura/auth/handler.py
clear_api_keys ¶
Clear all stored tokens from memory and storage backend.
Raises:
| Type | Description |
|---|---|
KeyringError
|
If there's an error clearing from keyring (when using keyring backend) |
Source code in src/miura/auth/handler.py
get_api_key_info ¶
Get information about the current refresh token and access token.
Returns:
| Name | Type | Description |
|---|---|---|
dict |
Dict[str, Any]
|
Token information including source (env var, keyring, etc.) |
Source code in src/miura/auth/handler.py
get_api_key_details ¶
Get detailed information about the current refresh token including JWT payload.
Returns:
| Name | Type | Description |
|---|---|---|
dict |
Dict[str, Any]
|
Detailed token information including JWT claims |
Raises:
| Type | Description |
|---|---|
ApiKeyNotFoundError
|
If no refresh token is found |
ApiKeyInvalidError
|
If refresh token format is invalid |
Source code in src/miura/auth/handler.py
408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 | |
JWTUtils ¶
Utilities for JWT token handling.
Source code in src/miura/auth/jwt.py
17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 | |
parse_jwt_payload
staticmethod
¶
Parse a JWT api key and extract its payload.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
api_key
|
str
|
JWT api key string |
required |
Returns:
| Name | Type | Description |
|---|---|---|
dict |
Dict[str, Any]
|
API key payload |
Raises:
| Type | Description |
|---|---|
ApiKeyInvalidError
|
If api key is malformed |
Source code in src/miura/auth/jwt.py
validate_jwt_format
staticmethod
¶
Validate that an api key has the basic JWT format.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
api_key
|
str
|
API key string to validate |
required |
Raises:
| Type | Description |
|---|---|
ApiKeyInvalidError
|
If api key format is invalid |
Source code in src/miura/auth/jwt.py
get_expiration_time
staticmethod
¶
Extract expiration time from JWT api key.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
api_key
|
str
|
JWT api key string |
required |
Returns:
| Name | Type | Description |
|---|---|---|
float |
Optional[float]
|
Expiration timestamp, or None if not found |
Source code in src/miura/auth/jwt.py
is_expired
staticmethod
¶
Check if a JWT token is expired or will expire soon.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
api_key
|
str
|
JWT api key string |
required |
buffer_seconds
|
int
|
Buffer time in seconds before actual expiration |
300
|
Returns:
| Name | Type | Description |
|---|---|---|
bool |
bool
|
True if expired or expiring soon, False otherwise |
Source code in src/miura/auth/jwt.py
extract_user_info
staticmethod
¶
Extract user information from JWT payload.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
payload
|
Dict[str, Any]
|
JWT payload dictionary |
required |
Returns:
| Name | Type | Description |
|---|---|---|
dict |
Dict[str, Any]
|
User information extracted from payload |
Source code in src/miura/auth/jwt.py
has_offline_access
staticmethod
¶
Check if JWT payload has offline access scope.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
payload
|
Dict[str, Any]
|
JWT payload dictionary |
required |
Returns:
| Name | Type | Description |
|---|---|---|
bool |
bool
|
True if offline_access scope is present |
Source code in src/miura/auth/jwt.py
KeycloakClient ¶
Client for Keycloak token operations with retry logic.
Source code in src/miura/auth/keycloak.py
40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 | |
__init__ ¶
__init__(config_manager: Optional[ConfigurationManager] = None, retry_policy: Optional[RetryPolicy] = None, verify_ssl: bool = True) -> None
Initialize Keycloak client.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
config_manager
|
Optional[ConfigurationManager]
|
Optional ConfigurationManager instance |
None
|
retry_policy
|
Optional[RetryPolicy]
|
Optional RetryPolicy (uses default from config if not provided) |
None
|
verify_ssl
|
bool
|
Whether to verify SSL certificates (default: True) |
True
|
Source code in src/miura/auth/keycloak.py
_get_http_client ¶
Get or create httpx client with connection pooling.
Source code in src/miura/auth/keycloak.py
_get_retry_policy ¶
Get retry policy from config or use default.
Source code in src/miura/auth/keycloak.py
_get_config ¶
Resolve the effective Keycloak configuration from InternalConfig.
Returns:
| Type | Description |
|---|---|
Dict[str, Any]
|
Dict[str, Any]: Mapping with keys base_url, realm, client_id, timeout_connect, timeout_read. |
Raises:
| Type | Description |
|---|---|
ValidationError
|
If configuration is invalid |
Source code in src/miura/auth/keycloak.py
_map_httpx_error ¶
Map httpx exceptions to shared exception hierarchy.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
error
|
Exception
|
httpx exception |
required |
endpoint
|
str
|
Endpoint URL for context |
required |
Returns:
| Type | Description |
|---|---|
Exception
|
Appropriate NexusError subclass |
Source code in src/miura/auth/keycloak.py
176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 | |
refresh_access_token ¶
Use refresh token to get a fresh access token from Keycloak.
Implements retry logic using shared RetryPolicy.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
refresh_token
|
str
|
The refresh token to use |
required |
Returns:
| Name | Type | Description |
|---|---|---|
str |
str
|
Fresh access token |
Raises:
| Type | Description |
|---|---|
PermissionError
|
If authentication fails (401) |
NetworkError
|
If network request fails |
TimeoutError
|
If request times out |
ApiKeyInvalidError
|
If token is invalid |
Source code in src/miura/auth/keycloak.py
286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 | |
close ¶
__enter__ ¶
TokenManager ¶
Manages authentication tokens in memory.
Source code in src/miura/auth/token.py
set_access_token ¶
invalidate_access_token ¶
Clear the cached access token with an optional log.
set_refresh_token ¶
set_refresh_token(token: Optional[str], *, reason: Optional[str] = None, force_invalidate: bool = False) -> Optional[str]
Update the cached refresh token and, when appropriate, invalidate the access token cache.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
token
|
Optional[str]
|
New refresh token value (or None to clear). |
required |
reason
|
Optional[str]
|
Optional message to log when invalidating the access token. |
None
|
force_invalidate
|
bool
|
When True, clears cached access token even if the refresh token is unchanged. |
False
|
Source code in src/miura/auth/token.py
clear_all ¶
Result ¶
Bases: BaseModel
Result schema for command output.
Source code in src/miura/auth/models.py
TokenDetails ¶
Bases: BaseModel
Token details schema for JSON output.
Source code in src/miura/auth/models.py
auth ¶
Manage authentication api keys.
Source code in src/miura/auth/cli.py
get_exit_code ¶
Map NexusError codes to deterministic exit codes.
Exit codes: - 0: Success - 1: Generic error - 2: Usage/non-interactive violation - 3: Auth invalid/expired - 4: Network/timeout - 5: Keyring/backend error - 6: Config invalid
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
error
|
NexusError
|
NexusError instance |
required |
Returns:
| Type | Description |
|---|---|
int
|
Exit code integer |
Source code in src/miura/auth/exceptions.py
get_auth_api_key ¶
Get an access token for API authentication.
SSL verification for Keycloak can be controlled via MIURA_KEYCLOAK_VERIFY_SSL environment variable. Defaults to True if not set.
Source code in src/miura/auth/handler.py
get_nexus_refresh_token ¶
Resolve the refresh/offline JWT used for Nexus API auth (env, then miura-auth storage).
Does not call Keycloak; same source order as :meth:AuthHandler.get_auth_api_key uses
before refreshing access tokens. Intended for callers that must forward this credential
(e.g. user-delegated DPD recipe execution).
Source code in src/miura/auth/handler.py
set_auth_api_key ¶
Store a refresh token in storage backend.
Source code in src/miura/auth/handler.py
clear_api_keys ¶
Clear all stored tokens from memory and storage backend.
Source code in src/miura/auth/handler.py
get_api_key_info ¶
Get information about the current refresh token and access token.
Source code in src/miura/auth/handler.py
get_api_key_details ¶
Get detailed information about the current refresh token including JWT payload.
Source code in src/miura/auth/handler.py
redact_token ¶
Redact a token for safe display in logs and output.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
token
|
Optional[str]
|
Token string to redact |
required |
Returns:
| Type | Description |
|---|---|
str
|
Redacted token string (first 4, last 4 chars) or placeholder |
Source code in src/miura/auth/utils.py
set_api_key ¶
Set API key programmatically.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
api_key
|
str
|
API key to store |
required |
storage
|
Literal['file', 'keyring', 'none']
|
Storage backend to use |
'file'
|
Returns:
| Type | Description |
|---|---|
Result
|
Result with status and message |
Raises:
| Type | Description |
|---|---|
ApiKeyInvalidError
|
If token format is invalid |
KeyringError
|
If storage fails |
Source code in src/miura/auth/core.py
get_token_details ¶
Get token details programmatically.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
storage
|
Literal['file', 'keyring', 'none']
|
Storage backend to use |
'file'
|
Returns:
| Type | Description |
|---|---|
TokenDetails
|
TokenDetails with all token information |
Raises:
| Type | Description |
|---|---|
ApiKeyNotFoundError
|
If no token is found |
ApiKeyInvalidError
|
If token is invalid |
Source code in src/miura/auth/core.py
delete_api_key ¶
Delete API key programmatically.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
storage
|
Literal['file', 'keyring', 'none']
|
Storage backend to use |
'file'
|
Returns:
| Type | Description |
|---|---|
Result
|
Result with status and message |
Source code in src/miura/auth/core.py
test_auth ¶
Test authentication programmatically.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
ping_api
|
bool
|
If True, test API connectivity in addition to auth |
False
|
storage
|
Literal['file', 'keyring', 'none']
|
Storage backend to use |
'file'
|
Returns:
| Type | Description |
|---|---|
Result
|
Result with status and message |
Raises:
| Type | Description |
|---|---|
ApiKeyNotFoundError
|
If no token is found |
ApiKeyInvalidError
|
If token is invalid |
NetworkError
|
If API connectivity test fails |
Source code in src/miura/auth/core.py
129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 | |
get_user_info ¶
Get current user identity programmatically.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
storage
|
Literal['file', 'keyring', 'none']
|
Storage backend to use |
'file'
|
Returns:
| Type | Description |
|---|---|
dict
|
Dictionary with user information (name, email, username) |
Raises:
| Type | Description |
|---|---|
ApiKeyNotFoundError
|
If no token is found |
ApiKeyInvalidError
|
If token is invalid |
Source code in src/miura/auth/core.py
__getattr__ ¶
Lazy import KeyringManager when accessed.