# `AshAuthentication.Strategy.DynamicOidc`
[🔗](https://github.com/team-alembic/ash_authentication/blob/main/lib/ash_authentication/strategies/dynamic_oidc.ex#L5)

Strategy for authenticating against arbitrary OpenID Connect providers
whose configuration lives in a database table rather than in your
application's compile-time DSL.

This is the building block for B2B/multi-tenant SSO patterns: each row in
your `OidcConnection` resource is one customer's IdP configuration
(`base_url`, `client_id`, `client_secret`, plus optional UI metadata).
At sign-in time the strategy queries the resource — typically scoped by
the current Ash tenant — and runs the standard OIDC flow against the
matched row.

## Setup

First, define a connection resource using
`AshAuthentication.OidcConnection`:

```elixir
defmodule MyApp.Accounts.OidcConnection do
  use Ash.Resource,
    data_layer: AshPostgres.DataLayer,
    extensions: [AshAuthentication.OidcConnection],
    domain: MyApp.Accounts

  oidc_connection do
    domain MyApp.Accounts
  end

  postgres do
    table "oidc_connections"
    repo MyApp.Repo
  end
end
```

Then add the strategy to your user resource:

```elixir
authentication do
  strategies do
    dynamic_oidc :sso do
      connection_resource MyApp.Accounts.OidcConnection
      identity_resource MyApp.Accounts.UserIdentity
      redirect_uri MyApp.Secrets
    end
  end
end
```

## URL shape

The strategy generates two routes:

  - `GET /<subject>/<strategy_name>/:connection_id/request` — initiate
    sign-in for a specific connection (the user/UI is responsible for
    knowing which connection_id to send to).
  - `GET /<subject>/<strategy_name>/callback` — single, shared callback
    URL. Each customer's IdP admin only ever needs to register *this*
    URL as their redirect URI. The connection_id is remembered between
    request and callback via the user's session.

## Tenant context

If your connection resource is multitenant, the strategy will scope the
lookup using the tenant set on the conn (`Ash.PlugHelpers.set_tenant/2`).
Set the tenant **upstream** of the auth router — typically in a Phoenix
plug that maps subdomain or header to your tenant. If no tenant is set
and the resource is multitenant, the lookup will fail.

Non-multitenant connection resources are also supported — the strategy
simply queries globally.

## More documentation

- `AshAuthentication.OidcConnection` — the resource extension this
  strategy depends on.
- `AshAuthentication.Strategy.Oidc` — the underlying compile-time OIDC
  strategy. The runtime behaviour is identical aside from where the
  config comes from.

# `t`

```elixir
@type t() :: %AshAuthentication.Strategy.DynamicOidc{
  __connection_id__: term(),
  __spark_metadata__: Spark.Dsl.Entity.spark_meta(),
  assent_strategy: module(),
  auth_method: term(),
  authorization_params: keyword() | {module(), keyword()},
  authorize_url: term(),
  base_url: term(),
  client_authentication_method: nil | binary(),
  client_id: term(),
  client_secret: term(),
  code_verifier: term(),
  connection_resource: module(),
  icon: atom(),
  id_token_signed_response_alg: binary(),
  id_token_ttl_seconds: nil | pos_integer(),
  identity_relationship_name: atom(),
  identity_relationship_user_id_attribute: atom(),
  identity_resource: module() | false,
  name: atom(),
  nonce: boolean() | nil | binary() | {module(), keyword()},
  openid_configuration: nil | map(),
  openid_configuration_uri: nil | binary() | {module(), keyword()},
  prevent_hijacking?: boolean(),
  private_key: term(),
  private_key_id: term(),
  private_key_path: term(),
  provider: atom(),
  redirect_uri: nil | binary() | {module(), keyword()},
  register_action_name: atom(),
  registration_enabled?: boolean(),
  resource: module(),
  session_identifier: nil | :unsafe | :jti,
  sign_in_action_name: atom(),
  site: term(),
  strategy_module: module(),
  team_id: term(),
  token_url: term(),
  trusted_audiences: nil | [String.t()] | {module(), keyword()},
  user_url: term()
}
```

# `transform`

# `verify`

---

*Consult [api-reference.md](api-reference.md) for complete listing*
