콘텐츠로 이동

spakky-oidc

OIDC bearer 인증 provider 플러그인 API입니다.

spakky.plugins.oidc

OIDC bearer authentication provider plugin public API.

OIDC_AUTH_PROVIDER_ID = 'provider:spakky-oidc' module-attribute

Stable auth provider id advertised by spakky-oidc.

DEFAULT_RETAINED_CLAIMS = ('sub', 'iss', 'aud', 'azp', 'email', 'name', 'preferred_username') module-attribute

Safe claim names retained in AuthContext; raw token material is excluded.

AbstractSpakkyOidcError

Bases: AbstractSpakkyFrameworkError

Base class for spakky-oidc provider errors.

OidcCredentialError

Bases: AbstractSpakkyOidcError

Raised when the credential carrier is not a usable bearer token.

OidcDiscoveryError

Bases: AbstractSpakkyOidcError

Raised when OIDC discovery metadata cannot be loaded or trusted.

OidcJwksError

Bases: AbstractSpakkyOidcError

Raised when JWKS keys cannot validate the bearer credential.

OidcTokenValidationError

Bases: AbstractSpakkyOidcError

Raised when JWT claims or signatures fail OIDC validation.

OidcAuthenticationProvider(config)

Bases: IAuthenticationProvider

OIDC JWT bearer implementation of the provider-neutral auth port.

Source code in plugins/spakky-oidc/src/spakky/plugins/oidc/provider.py
def __init__(
    self,
    config: OidcProviderConfig,
) -> None:
    self._config = config

authenticate(credential, invocation)

Authenticate an OIDC bearer credential and return AuthContext.

Source code in plugins/spakky-oidc/src/spakky/plugins/oidc/provider.py
@override
def authenticate(
    self,
    credential: CredentialCarrier,
    invocation: AuthInvocation,
) -> AuthContext:
    """Authenticate an OIDC bearer credential and return AuthContext."""
    if not self._config.provider_available:
        raise OidcDiscoveryError()
    token = self._bearer_token(credential)
    metadata = self._discovery_metadata()
    jwk = self._matching_jwk(token, metadata.jwks_uri)
    claims = self._verified_claims(token, jwk, metadata.issuer)
    return self._auth_context_from_claims(claims)

authenticate_result(credential, invocation)

Authenticate a bearer token and map failures to auth decisions.

Source code in plugins/spakky-oidc/src/spakky/plugins/oidc/provider.py
def authenticate_result(
    self,
    credential: CredentialCarrier,
    invocation: AuthInvocation,
) -> OidcAuthenticationResult:
    """Authenticate a bearer token and map failures to auth decisions."""
    try:
        auth_context = self.authenticate(credential, invocation)
    except OidcCredentialError:
        return OidcAuthenticationResult(
            decision=AuthorizationDecision.challenge(
                AuthorizationReasonCode.MISSING_CREDENTIAL
            )
        )
    except OidcTokenValidationError:
        return OidcAuthenticationResult(
            decision=AuthorizationDecision.challenge(
                AuthorizationReasonCode.INVALID_CREDENTIAL
            )
        )
    except OidcJwksError:
        return OidcAuthenticationResult(
            decision=AuthorizationDecision.challenge(
                AuthorizationReasonCode.INVALID_CREDENTIAL
            )
        )
    except OidcDiscoveryError:
        return OidcAuthenticationResult(
            decision=AuthorizationDecision.error(
                AuthorizationReasonCode.VERIFICATION_PROVIDER_UNAVAILABLE
            )
        )
    return OidcAuthenticationResult(
        decision=AuthorizationDecision.allow(),
        auth_context=auth_context,
    )

OidcAuthenticationResult(*, decision, auth_context=None) dataclass

Decision plus optional AuthContext produced by bearer authentication.

decision instance-attribute

ALLOW, CHALLENGE, or ERROR decision for the authentication attempt.

auth_context = None class-attribute instance-attribute

Authenticated context when decision is ALLOW.

OidcDiscoveryMetadata(*, issuer, jwks_uri) dataclass

Trusted subset of OIDC discovery metadata.

issuer instance-attribute

Issuer reported by the discovery document.

jwks_uri instance-attribute

JWKS endpoint used to select token verification keys.

OidcProviderConfig()

Bases: BaseSettings

Runtime config for OIDC bearer authentication.

Source code in plugins/spakky-oidc/src/spakky/plugins/oidc/provider.py
def __init__(self) -> None:
    super().__init__()

issuer = 'https://issuer.example.test' class-attribute instance-attribute

Expected issuer and base URL for discovery when discovery_url is omitted.

audience = 'spakky' class-attribute instance-attribute

Accepted audience value or values.

client_id = None class-attribute instance-attribute

Expected authorized party (azp) when the token carries it.

discovery_url = None class-attribute instance-attribute

Explicit OIDC discovery URL; defaults to issuer/.well-known/openid-configuration.

algorithm = 'RS256' class-attribute instance-attribute

Expected JWT signing algorithm.

clock_skew = timedelta(seconds=60) class-attribute instance-attribute

Allowed exp/nbf/iat clock skew.

retained_claim_names = DEFAULT_RETAINED_CLAIMS class-attribute instance-attribute

JWT claim names safe to retain on AuthContext.

roles_claim = 'roles' class-attribute instance-attribute

Claim containing role refs as a string or string array.

scopes_claim = 'scope' class-attribute instance-attribute

Claim containing scope refs as a space-delimited string or string array.

tenant_claim = 'tenant' class-attribute instance-attribute

Optional claim containing the tenant canonical ref.

display_name_claim = 'name' class-attribute instance-attribute

Optional claim containing a human-readable subject label.

json_fetcher = fetch_json_document class-attribute instance-attribute

Fetches discovery and JWKS JSON; injectable for deterministic tests.

provider_available = True class-attribute instance-attribute

Whether provider dependencies are usable at runtime.

fetch_json_document(url)

Fetch a JSON object from an OIDC metadata URL.

Source code in plugins/spakky-oidc/src/spakky/plugins/oidc/provider.py
def fetch_json_document(url: str) -> JsonObject:
    """Fetch a JSON object from an OIDC metadata URL."""
    try:
        with urlopen(url, timeout=5) as response:
            payload = json.load(response)
    except (OSError, URLError, json.JSONDecodeError) as exc:
        raise OidcDiscoveryError() from exc
    if isinstance(payload, dict):
        return _string_keyed_dict(payload)
    raise OidcDiscoveryError()

oidc_auth_provider_contribution()

Return the auth capabilities contributed by spakky-oidc.

Source code in plugins/spakky-oidc/src/spakky/plugins/oidc/provider.py
@Pod(name="spakky_oidc_auth_provider_contribution")
def oidc_auth_provider_contribution() -> AuthProviderContribution:
    """Return the auth capabilities contributed by spakky-oidc."""
    return AuthProviderContribution(
        provider_id=OIDC_AUTH_PROVIDER_ID,
        capabilities=frozenset({AuthCapability.AUTHENTICATION}),
    )

spakky.plugins.oidc.main

Plugin initialization for OIDC bearer authentication.

initialize(app)

Register OIDC configuration and authentication provider binding.

Source code in plugins/spakky-oidc/src/spakky/plugins/oidc/main.py
def initialize(app: SpakkyApplication) -> None:
    """Register OIDC configuration and authentication provider binding."""
    app.add(OidcProviderConfig)
    app.add(OidcAuthenticationProvider)
    app.container.bind_to_type(IAuthenticationProvider, OidcAuthenticationProvider)

spakky.plugins.oidc.provider

OIDC bearer authentication provider.

OIDC_AUTH_PROVIDER_ID = 'provider:spakky-oidc' module-attribute

Stable auth provider id advertised by spakky-oidc.

DEFAULT_RETAINED_CLAIMS = ('sub', 'iss', 'aud', 'azp', 'email', 'name', 'preferred_username') module-attribute

Safe claim names retained in AuthContext; raw token material is excluded.

OidcProviderConfig()

Bases: BaseSettings

Runtime config for OIDC bearer authentication.

Source code in plugins/spakky-oidc/src/spakky/plugins/oidc/provider.py
def __init__(self) -> None:
    super().__init__()

issuer = 'https://issuer.example.test' class-attribute instance-attribute

Expected issuer and base URL for discovery when discovery_url is omitted.

audience = 'spakky' class-attribute instance-attribute

Accepted audience value or values.

client_id = None class-attribute instance-attribute

Expected authorized party (azp) when the token carries it.

discovery_url = None class-attribute instance-attribute

Explicit OIDC discovery URL; defaults to issuer/.well-known/openid-configuration.

algorithm = 'RS256' class-attribute instance-attribute

Expected JWT signing algorithm.

clock_skew = timedelta(seconds=60) class-attribute instance-attribute

Allowed exp/nbf/iat clock skew.

retained_claim_names = DEFAULT_RETAINED_CLAIMS class-attribute instance-attribute

JWT claim names safe to retain on AuthContext.

roles_claim = 'roles' class-attribute instance-attribute

Claim containing role refs as a string or string array.

scopes_claim = 'scope' class-attribute instance-attribute

Claim containing scope refs as a space-delimited string or string array.

tenant_claim = 'tenant' class-attribute instance-attribute

Optional claim containing the tenant canonical ref.

display_name_claim = 'name' class-attribute instance-attribute

Optional claim containing a human-readable subject label.

json_fetcher = fetch_json_document class-attribute instance-attribute

Fetches discovery and JWKS JSON; injectable for deterministic tests.

provider_available = True class-attribute instance-attribute

Whether provider dependencies are usable at runtime.

OidcAuthenticationResult(*, decision, auth_context=None) dataclass

Decision plus optional AuthContext produced by bearer authentication.

decision instance-attribute

ALLOW, CHALLENGE, or ERROR decision for the authentication attempt.

auth_context = None class-attribute instance-attribute

Authenticated context when decision is ALLOW.

OidcDiscoveryMetadata(*, issuer, jwks_uri) dataclass

Trusted subset of OIDC discovery metadata.

issuer instance-attribute

Issuer reported by the discovery document.

jwks_uri instance-attribute

JWKS endpoint used to select token verification keys.

OidcAuthenticationProvider(config)

Bases: IAuthenticationProvider

OIDC JWT bearer implementation of the provider-neutral auth port.

Source code in plugins/spakky-oidc/src/spakky/plugins/oidc/provider.py
def __init__(
    self,
    config: OidcProviderConfig,
) -> None:
    self._config = config

authenticate(credential, invocation)

Authenticate an OIDC bearer credential and return AuthContext.

Source code in plugins/spakky-oidc/src/spakky/plugins/oidc/provider.py
@override
def authenticate(
    self,
    credential: CredentialCarrier,
    invocation: AuthInvocation,
) -> AuthContext:
    """Authenticate an OIDC bearer credential and return AuthContext."""
    if not self._config.provider_available:
        raise OidcDiscoveryError()
    token = self._bearer_token(credential)
    metadata = self._discovery_metadata()
    jwk = self._matching_jwk(token, metadata.jwks_uri)
    claims = self._verified_claims(token, jwk, metadata.issuer)
    return self._auth_context_from_claims(claims)

authenticate_result(credential, invocation)

Authenticate a bearer token and map failures to auth decisions.

Source code in plugins/spakky-oidc/src/spakky/plugins/oidc/provider.py
def authenticate_result(
    self,
    credential: CredentialCarrier,
    invocation: AuthInvocation,
) -> OidcAuthenticationResult:
    """Authenticate a bearer token and map failures to auth decisions."""
    try:
        auth_context = self.authenticate(credential, invocation)
    except OidcCredentialError:
        return OidcAuthenticationResult(
            decision=AuthorizationDecision.challenge(
                AuthorizationReasonCode.MISSING_CREDENTIAL
            )
        )
    except OidcTokenValidationError:
        return OidcAuthenticationResult(
            decision=AuthorizationDecision.challenge(
                AuthorizationReasonCode.INVALID_CREDENTIAL
            )
        )
    except OidcJwksError:
        return OidcAuthenticationResult(
            decision=AuthorizationDecision.challenge(
                AuthorizationReasonCode.INVALID_CREDENTIAL
            )
        )
    except OidcDiscoveryError:
        return OidcAuthenticationResult(
            decision=AuthorizationDecision.error(
                AuthorizationReasonCode.VERIFICATION_PROVIDER_UNAVAILABLE
            )
        )
    return OidcAuthenticationResult(
        decision=AuthorizationDecision.allow(),
        auth_context=auth_context,
    )

fetch_json_document(url)

Fetch a JSON object from an OIDC metadata URL.

Source code in plugins/spakky-oidc/src/spakky/plugins/oidc/provider.py
def fetch_json_document(url: str) -> JsonObject:
    """Fetch a JSON object from an OIDC metadata URL."""
    try:
        with urlopen(url, timeout=5) as response:
            payload = json.load(response)
    except (OSError, URLError, json.JSONDecodeError) as exc:
        raise OidcDiscoveryError() from exc
    if isinstance(payload, dict):
        return _string_keyed_dict(payload)
    raise OidcDiscoveryError()

oidc_auth_provider_contribution()

Return the auth capabilities contributed by spakky-oidc.

Source code in plugins/spakky-oidc/src/spakky/plugins/oidc/provider.py
@Pod(name="spakky_oidc_auth_provider_contribution")
def oidc_auth_provider_contribution() -> AuthProviderContribution:
    """Return the auth capabilities contributed by spakky-oidc."""
    return AuthProviderContribution(
        provider_id=OIDC_AUTH_PROVIDER_ID,
        capabilities=frozenset({AuthCapability.AUTHENTICATION}),
    )

spakky.plugins.oidc.error

OIDC provider-specific errors.

AbstractSpakkyOidcError

Bases: AbstractSpakkyFrameworkError

Base class for spakky-oidc provider errors.

OidcDiscoveryError

Bases: AbstractSpakkyOidcError

Raised when OIDC discovery metadata cannot be loaded or trusted.

OidcJwksError

Bases: AbstractSpakkyOidcError

Raised when JWKS keys cannot validate the bearer credential.

OidcCredentialError

Bases: AbstractSpakkyOidcError

Raised when the credential carrier is not a usable bearer token.

OidcTokenValidationError

Bases: AbstractSpakkyOidcError

Raised when JWT claims or signatures fail OIDC validation.

spakky.plugins.oidc.contributions.auth

Auth feature contribution for the OIDC provider.

initialize(app)

Register OIDC auth capability metadata.

Source code in plugins/spakky-oidc/src/spakky/plugins/oidc/contributions/auth.py
7
8
9
def initialize(app: SpakkyApplication) -> None:
    """Register OIDC auth capability metadata."""
    app.add(oidc_auth_provider_contribution)