Skip to content

Identity Capability

IdentityCapability is the contract base for a capability that authenticates a specific user to a remote via OAuth 2.0, OIDC, or an OIDC-shaped device-code flow (e.g. AWS IAM Identity Center). Bind it with a Capability(kind='identity', handler=...) and set the plugin manifest's auth_type to match ('oauth2', 'oidc', or 'aws-iam-ic').

Identity capabilities exist so that other capabilities — typically deployment — can act as the human user rather than as a shared service principal. After a user links their account, the host materializes their credentials into PluginContext.identity for a capability that sets requires_identity=True. Identity is Integration-wide, so its capability is typically declared with project_scoped=False.

Surfaces: api.

See Authoring Plugins for the manifest, capabilities, context, credential decryption, and error conventions shared by every plugin.

from imbi.common.plugins import (
    AuthorizationRequest,
    IdentityCapability,
    IdentityCredentials,
    IdentityProfile,
    PluginContext,
)


class GitHubIdentity(IdentityCapability):
    async def authorization_request(
        self,
        ctx: PluginContext,
        credentials: dict[str, str],
        redirect_uri: str,
        scopes: list[str] | None = None,
    ) -> AuthorizationRequest:
        ...

    async def exchange_code(
        self,
        ctx: PluginContext,
        credentials: dict[str, str],
        code: str,
        redirect_uri: str,
        code_verifier: str | None = None,
    ) -> tuple[IdentityProfile, IdentityCredentials]:
        ...

    async def refresh(
        self,
        ctx: PluginContext,
        credentials: dict[str, str],
        refresh_token: str,
    ) -> IdentityCredentials:
        ...

Method contracts

  • authorization_request — return what the host needs to start the flow: the authorization_url to redirect the browser to, an opaque state, and (for PKCE) a code_verifier. For non-redirect device flows return a PollingDescriptor in polling; the UI then polls /me/identities/{integration_id}/poll and surfaces the user_code. If the capability mints credentials on the fly (e.g. OIDC dynamic-client registration), return them in registered_credentials so the host persists them for the matching exchange_code / refresh calls.
  • exchange_code — exchange the authorization code (or completed device authorization) for a normalized IdentityProfile and the IdentityCredentials to store. While an out-of-band step is still pending, raise IdentityAuthorizationPending; once the device code has expired, raise IdentityAuthorizationExpired.
  • refresh — exchange a stored refresh token for fresh IdentityCredentials.
  • revoke — optional best-effort revocation; the default is a no-op for IdPs without a revoke endpoint.
  • materialize — optional hook for capabilities that must exchange the IdP token for a backend-specific credential at call time (AWS IAM IC overrides this to call GetRoleCredentials and return STS keys in IdentityCredentials.extra). The default returns the stored connection unchanged. It also receives two keyword-only arguments: db, the host's Graph, and identity_options, the identity capability's own resolved option values.

Hints

  • login_capable — the identity capability is usable as a sign-in provider for Imbi itself.
  • default_scopes — the scopes requested when none are supplied to authorization_request.
  • widget_text — body copy for the dashboard "unconnected integration" widget prompting the user to link.
  • cacheable — the host may cache reads from this capability.

The host persists per-user connections as IdentityConnection vertices. The core graph schema declares that label, so the plugin manifest does not declare it.

API reference

IdentityCapability

Bases: CapabilityHandler

Authenticate a specific user to a remote via OIDC, OAuth 2.0, or an OIDC-shaped device-code flow (e.g. AWS IAM Identity Center).

materialize async

materialize(
    ctx: PluginContext,
    credentials: dict[str, str],
    connection: IdentityCredentials,
    *,
    db: Any | None = None,
    identity_options: dict[str, Any] | None = None,
) -> IdentityCredentials

Exchange the IdP token for a backend-specific credential.

Default: return connection unchanged. AWS IAM IC overrides this to call GetRoleCredentials and return STS keys in IdentityCredentials.extra.

db is the host's :class:graph.Graph (typed loosely to keep this base module independent of the graph package). identity_options is the identity capability's own resolved option values.

Source code in libraries/common/src/imbi/common/plugins/base.py
async def materialize(
    self,
    ctx: PluginContext,
    credentials: dict[str, str],
    connection: IdentityCredentials,
    *,
    db: typing.Any | None = None,
    identity_options: dict[str, typing.Any] | None = None,
) -> IdentityCredentials:
    """Exchange the IdP token for a backend-specific credential.

    Default: return ``connection`` unchanged.  AWS IAM IC overrides
    this to call ``GetRoleCredentials`` and return STS keys in
    ``IdentityCredentials.extra``.

    ``db`` is the host's :class:`graph.Graph` (typed loosely to keep
    this base module independent of the graph package).
    ``identity_options`` is the identity capability's own resolved
    option values.
    """
    return connection

revoke async

revoke(
    ctx: PluginContext,
    credentials: dict[str, str],
    token: str,
) -> None

Best-effort revocation. Default no-op for IdPs without revoke.

Source code in libraries/common/src/imbi/common/plugins/base.py
async def revoke(
    self,
    ctx: PluginContext,
    credentials: dict[str, str],
    token: str,
) -> None:
    """Best-effort revocation. Default no-op for IdPs without revoke."""
    return None

IdentityProfile

Bases: BaseModel

Normalized profile returned after a successful identity flow.

IdentityCredentials

Bases: BaseModel

Materialized credentials handed to other capabilities.

Capabilities receive this in :class:PluginContext.identity when the assignment declares an identity Integration. The shape is close to the OAuth 2.0 RFC 6749 token response so most backends consume it directly. extra carries backend-specific keys (e.g. STS temp credentials for AWS IAM IC).

AuthorizationRequest

Bases: BaseModel

What the API needs to redirect the browser to start a flow.

PollingDescriptor

Bases: BaseModel

Descriptor for device-flow style polling.

Returned by identity capabilities whose authorization flow is not a redirect (e.g. AWS IAM Identity Center device authorization). The UI polls /me/identities/{integration_id}/poll every interval seconds, surfacing user_code to the user.