Ltix.StorageAdapter behaviour (Ltix v0.1.0)

Copy Markdown View Source

Defines callbacks for looking up registrations, deployments, and managing nonces.

Your application implements this behaviour to connect Ltix to your persistence layer. See the Storage Adapters guide for a complete Ecto-backed example.

Returning your own structs

get_registration/2 and get_deployment/2 can return any struct that implements Ltix.Registerable or Ltix.Deployable. Your struct is passed through to the Ltix.LaunchContext after a successful launch, so you can access your own fields (database IDs, tenant info, etc.) without an extra query.

Callback summary

CallbackCalled duringPurpose
get_registration/2Login initiationLook up a platform by issuer and optional client_id
get_deployment/2Launch validationLook up a deployment by registration and deployment_id
store_nonce/2Login initiationPersist a nonce for later verification
validate_nonce/2Launch validationVerify a nonce was issued by the tool, then consume it

Summary

Callbacks

Look up a deployment by registration and deployment_id.

Look up a platform registration by issuer and client_id.

Persist a nonce for later verification.

Verify a nonce from the ID Token and consume it.

Callbacks

get_deployment(registration, deployment_id)

@callback get_deployment(
  registration :: Ltix.Registration.t(),
  deployment_id :: String.t()
) ::
  {:ok, Ltix.Deployable.t()} | {:error, :not_found}

Look up a deployment by registration and deployment_id.

The deployment_id is case-sensitive and assigned by the platform. The registration parameter is the resolved Ltix.Registration, not the original struct returned by get_registration/2.

Return any struct that implements Ltix.Deployable. The library validates it via the protocol and preserves your original struct in the Ltix.LaunchContext.

get_registration(issuer, client_id)

@callback get_registration(issuer :: String.t(), client_id :: String.t() | nil) ::
  {:ok, Ltix.Registerable.t()} | {:error, :not_found}

Look up a platform registration by issuer and client_id.

The client_id may be nil when the platform doesn't include it in the login request. Your adapter must handle both cases.

Return any struct that implements Ltix.Registerable. The library extracts the Ltix.Registration it needs via the protocol and preserves your original struct in the Ltix.LaunchContext.

store_nonce(nonce, registration)

@callback store_nonce(nonce :: String.t(), registration :: Ltix.Registration.t()) :: :ok

Persist a nonce for later verification.

Called during login initiation. The nonce is generated by the library and must be stored so that validate_nonce/2 can verify it was issued by the tool and has not been replayed.

validate_nonce(nonce, registration)

@callback validate_nonce(nonce :: String.t(), registration :: Ltix.Registration.t()) ::
  :ok | {:error, :nonce_already_used | :nonce_not_found}

Verify a nonce from the ID Token and consume it.

The implementation must check two things:

  1. The nonce was previously stored by store_nonce/2
  2. The nonce has not already been consumed (replay prevention)

After successful validation, mark the nonce as consumed so it cannot be reused.