defmodule Oidcc.TokenIntrospection do use TelemetryRegistry telemetry_event(%{ event: [:oidcc, :introspect_token, :start], description: "Emitted at the start of introspecting the token", measurements: "%{system_time: non_neg_integer(), monotonic_time: integer()}", metadata: "%{issuer: :uri_string.uri_string(), client_id: String.t()}" }) telemetry_event(%{ event: [:oidcc, :introspect_token, :stop], description: "Emitted at the end of introspecting the token", measurements: "%{duration: integer(), monotonic_time: integer()}", metadata: "%{issuer: :uri_string.uri_string(), client_id: String.t()}" }) telemetry_event(%{ event: [:oidcc, :introspect_token, :exception], description: "Emitted at the end of introspecting the token", measurements: "%{duration: integer(), monotonic_time: integer()}", metadata: "%{issuer: :uri_string.uri_string(), client_id: String.t()}" }) @moduledoc """ OAuth Token Introspection See https://datatracker.ietf.org/doc/html/rfc7662 ## Telemetry #{telemetry_docs()} """ @moduledoc since: "3.0.0" use Oidcc.RecordStruct, internal_name: :introspection, record_name: :oidcc_token_introspection, hrl: "include/oidcc_token_introspection.hrl" alias Oidcc.ClientContext alias Oidcc.Token @typedoc """ For details on the fields see: * https://datatracker.ietf.org/doc/html/rfc7662#section-2.2 """ @typedoc since: "3.0.0" @type t() :: %__MODULE__{ active: boolean(), client_id: binary(), exp: pos_integer() | :undefined, scope: :oidcc_scope.scopes(), username: binary() | :undefined, token_type: binary() | :undefined, iat: pos_integer() | :undefined, nbf: pos_integer() | :undefined, sub: binary() | :undefined, aud: binary() | :undefined, iss: binary() | :undefined, jti: binary() | :undefined, extra: %{binary() => term()} } @doc """ Introspect the given access token For a high level interface using `Oidcc.ProviderConfiguration.Worker` see `Oidcc.introspect_token/5`. ## Examples iex> {:ok, pid} = ...> Oidcc.ProviderConfiguration.Worker.start_link(%{ ...> issuer: "https://api.login.yahoo.com" ...> }) ...> ...> {:ok, client_context} = ...> Oidcc.ClientContext.from_configuration_worker( ...> pid, ...> "client_id", ...> "client_secret" ...> ) ...> ...> Oidcc.TokenIntrospection.introspect( ...> "access_token", ...> client_context ...> ) ...> # => {:ok, %Oidcc.TokenIntrospection{}} """ @doc since: "3.0.0" @spec introspect( token :: String.t() | Token.t(), client_context :: ClientContext.t(), opts :: :oidcc_token_introspection.opts() ) :: {:ok, t()} | {:error, :oidcc_token_introspection.error()} def introspect(token, client_context, opts \\ %{}) do client_context = ClientContext.struct_to_record(client_context) token = case token do token when is_binary(token) -> token %Token{} = token -> Token.struct_to_record(token) end with {:ok, introspection} <- :oidcc_token_introspection.introspect(token, client_context, opts) do {:ok, record_to_struct(introspection)} end end end