# `Oidcc`
[🔗](https://github.com/erlef/oidcc/blob/ee3434ddec86c14471af8f8a8f159971e654da3c
/lib/oidcc.ex#L4)

OpenID Connect High Level Interface

## Setup

    {:ok, _pid} =
      Oidcc.ProviderConfiguration.Worker.start_link(%{
      issuer: "https://accounts.google.com",
      name: MyApp.GoogleConfigProvider
    })

or via a supervisor

    Supervisor.init([
      {Oidcc.ProviderConfiguration.Worker, %{issuer: "https://accounts.google.com"}}
    ], strategy: :one_for_one)

## Global Configuration

* `max_clock_skew` (default `0`) - Maximum allowed clock skew for JWT
  `exp` / `nbf` validation, in seconds

# `client_credentials_token`
*since 3.0.0* 

```elixir
@spec client_credentials_token(
  provider_configuration_name :: GenServer.name(),
  client_id :: String.t(),
  client_secret :: String.t(),
  opts :: :oidcc_token.client_credentials_opts() | :oidcc_client_context.opts()
) ::
  {:ok, Oidcc.Token.t()}
  | {:error, :oidcc_client_context.error() | :oidcc_token.error()}
```

Retrieve Client Credential Token

See https://datatracker.ietf.org/doc/html/rfc6749#section-1.3.4

## Examples

    iex> {:ok, pid} =
    ...>   Oidcc.ProviderConfiguration.Worker.start_link(%{
    ...>     issuer: "https://erlef-test-w4a8z2.zitadel.cloud"
    ...>   })
    ...>
    ...> {:ok, %Oidcc.Token{}} =
    ...>   Oidcc.client_credentials_token(
    ...>     pid,
    ...>     System.fetch_env!("CLIENT_CREDENTIALS_CLIENT_ID"),
    ...>     System.fetch_env!("CLIENT_CREDENTIALS_CLIENT_SECRET"),
    ...>     %{scope: ["openid"]}
    ...>   )

# `create_redirect_url`
*since 3.0.0* 

```elixir
@spec create_redirect_url(
  provider_configuration_name :: GenServer.name(),
  client_id :: String.t(),
  client_secret :: String.t() | :unauthenticated,
  opts :: :oidcc_authorization.opts() | :oidcc_client_context.opts()
) :: {:ok, :uri_string.uri_string()} | {:error, :oidcc_client_context.error()}
```

Create Auth Redirect URL

## Examples

    iex> {:ok, pid} =
    ...>   Oidcc.ProviderConfiguration.Worker.start_link(%{
    ...>   issuer: "https://accounts.google.com"
    ...> })
    ...>
    ...> {:ok, _redirect_uri} =
    ...>   Oidcc.create_redirect_url(
    ...>     pid,
    ...>     "client_id",
    ...>     "client_secret",
    ...>     %{redirect_uri: "https://my.server/return"}
    ...>   )

# `initiate_logout_url`
*since 3.0.0* 

```elixir
@spec initiate_logout_url(
  token :: id_token | Oidcc.Token.t() | :undefined,
  provider_configuration_name :: GenServer.name(),
  client_id :: String.t(),
  opts :: :oidcc_logout.initiate_url_opts() | :oidcc_client_context.opts()
) ::
  {:ok, :uri_string.uri_string()}
  | {:error, :oidcc_client_context.error() | :oidcc_logout.error()}
when id_token: String.t()
```

Create Initiate URI for Relaying Party initiated Logout

See [https://openid.net/specs/openid-connect-rpinitiated-1_0.html#RPLogout]

## Examples

    iex> {:ok, pid} =
    ...>   Oidcc.ProviderConfiguration.Worker.start_link(%{
    ...>     issuer: "https://erlef-test-w4a8z2.zitadel.cloud"
    ...>   })
    ...>
    ...> # Get access_token from Oidcc.Token.retrieve/3
    ...> token = "token"
    ...>
    ...> {:ok, _redirect_uri} = Oidcc.initiate_logout_url(
    ...>   token,
    ...>   pid,
    ...>   "client_id"
    ...> )

# `introspect_token`
*since 3.0.0* 

```elixir
@spec introspect_token(
  access_token :: String.t() | Oidcc.Token.t(),
  provider_configuration_name :: GenServer.name(),
  client_id :: String.t(),
  client_secret :: String.t(),
  opts :: :oidcc_token_introspection.opts() | :oidcc_client_context.opts()
) ::
  {:ok, Oidcc.TokenIntrospection.t()}
  | {:error, :oidcc_client_context.error() | :oidcc_token_introspection.error()}
```

Introspect the given access token

## Examples

    iex> {:ok, pid} =
    ...>   Oidcc.ProviderConfiguration.Worker.start_link(%{
    ...>     issuer: "https://api.login.yahoo.com"
    ...>   })
    ...>
    ...> Oidcc.introspect_token(
    ...>   "access_token",
    ...>   pid,
    ...>   "client_id",
    ...>   "client_secret"
    ...> )
    ...> # => {:ok, %Oidcc.TokenIntrospection{}}

# `jwt_profile_token`
*since 3.0.0* 

```elixir
@spec jwt_profile_token(
  subject :: String.t(),
  provider_configuration_name :: GenServer.name(),
  client_id :: String.t(),
  client_secret :: String.t() | :unauthenticated,
  jwk :: JOSE.JWK.t(),
  opts :: :oidcc_token.jwt_profile_opts() | :oidcc_client_context.opts()
) ::
  {:ok, Oidcc.Token.t()}
  | {:error, :oidcc_client_context.error() | :oidcc_token.error()}
```

Retrieve JSON Web Token (JWT) Profile Token

https://datatracker.ietf.org/doc/html/rfc7523#section-4

## Examples

    iex> {:ok, pid} =
    ...>   Oidcc.ProviderConfiguration.Worker.start_link(%{
    ...>     issuer: "https://erlef-test-w4a8z2.zitadel.cloud"
    ...>   })
    ...>
    ...> %{"key" => key, "keyId" => kid, "userId" => subject} = "JWT_PROFILE"
    ...>   |> System.fetch_env!()
    ...>   |> JOSE.decode()
    ...>
    ...> jwk = JOSE.JWK.from_pem(key)
    ...>
    ...> {:ok, %Oidcc.Token{}} =
    ...>   Oidcc.jwt_profile_token(
    ...>     subject,
    ...>     pid,
    ...>     "JWT Profile Test",
    ...>     "client_secret",
    ...>     jwk,
    ...>     %{scope: ["openid", "urn:zitadel:iam:org:project:id:zitadel:aud"], kid: kid}
    ...>   )

# `refresh_token`
*since 3.0.0* 

```elixir
@spec refresh_token(
  refresh_token :: String.t(),
  provider_configuration_name :: GenServer.name(),
  client_id :: String.t(),
  client_secret :: String.t() | :unauthenticated,
  opts :: :oidcc_token.refresh_opts() | :oidcc_client_context.opts()
) :: {:ok, Oidcc.Token.t()} | {:error, :oidcc_token.error()}
@spec refresh_token(
  token :: Oidcc.Token.t(),
  provider_configuration_name :: GenServer.name(),
  client_id :: String.t(),
  client_secret :: String.t() | :unauthenticated,
  opts :: :oidcc_token.refresh_opts_no_sub() | :oidcc_client_context.opts()
) ::
  {:ok, Oidcc.Token.t()}
  | {:error, :oidcc_client_context.error() | :oidcc_token.error()}
```

Refresh Token

## Examples

    iex> {:ok, pid} =
    ...>   Oidcc.ProviderConfiguration.Worker.start_link(%{
    ...>     issuer: "https://api.login.yahoo.com"
    ...>   })
    ...>
    ...> # Get refresh_token from redirect
    ...> refresh_token = "refresh_token"
    ...>
    ...> Oidcc.refresh_token(
    ...>   refresh_token,
    ...>   pid,
    ...>   "client_id",
    ...>   "client_secret",
    ...>   %{expected_subject: "sub_from_initial_id_token"}
    ...> )
    ...> # => {:ok, %Oidcc.Token{}}

# `retrieve_token`
*since 3.0.0* 

```elixir
@spec retrieve_token(
  auth_code :: String.t(),
  provider_configuration_name :: GenServer.name(),
  client_id :: String.t(),
  client_secret :: String.t() | :unauthenticated,
  opts :: :oidcc_token.retrieve_opts() | :oidcc_client_context.opts()
) ::
  {:ok, Oidcc.Token.t()}
  | {:error, :oidcc_client_context.error() | :oidcc_token.error()}
```

retrieve the token using the authcode received before and directly validate
the result.

the authcode was sent to the local endpoint by the OpenId Connect provider,
using redirects

## Examples

    iex> {:ok, pid} =
    ...>   Oidcc.ProviderConfiguration.Worker.start_link(%{
    ...>     issuer: "https://api.login.yahoo.com"
    ...>   })
    ...>
    ...> # Get auth_code from redirect
    ...> auth_code = "auth_code"
    ...>
    ...> Oidcc.retrieve_token(
    ...>   auth_code,
    ...>   pid,
    ...>   "client_id",
    ...>   "client_secret",
    ...>   %{redirect_uri: "https://my.server/return"}
    ...> )
    ...> # => {:ok, %Oidcc.Token{}}

# `retrieve_userinfo`
*since 3.0.0* 

```elixir
@spec retrieve_userinfo(
  token :: Oidcc.Token.t(),
  provider_configuration_name :: GenServer.name(),
  client_id :: String.t(),
  client_secret :: String.t() | :unauthenticated,
  opts :: :oidcc_userinfo.retrieve_opts_no_sub() | :oidcc_client_context.opts()
) :: {:ok, :oidcc_jwt_util.claims()} | {:error, :oidcc_userinfo.error()}
@spec retrieve_userinfo(
  access_token :: String.t(),
  provider_configuration_name :: GenServer.name(),
  client_id :: String.t(),
  client_secret :: String.t(),
  opts :: :oidcc_userinfo.retrieve_opts() | :oidcc_client_context.opts()
) ::
  {:ok, :oidcc_jwt_util.claims()}
  | {:error, :oidcc_client_context.error() | :oidcc_userinfo.error()}
```

Load userinfo for the given token

## Examples

    iex> {:ok, pid} =
    ...>   Oidcc.ProviderConfiguration.Worker.start_link(%{
    ...>     issuer: "https://api.login.yahoo.com"
    ...>   })
    ...>
    ...> # Get access_token from Oidcc.Token.retrieve/3
    ...> access_token = "access_token"
    ...>
    ...> Oidcc.retrieve_userinfo(
    ...>   access_token,
    ...>   pid,
    ...>   "client_id",
    ...>   "client_secret",
    ...>   %{expected_subject: "sub"}
    ...> )
    ...> # => {:ok, %{"sub" => "sub"}}

---

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