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 since: "3.0.0"
@type t() :: %__MODULE__{
active: boolean(),
client_id: binary(),
exp: pos_integer(),
scope: :oidcc_scope.scopes(),
username: binary()
}
@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