Packages
indieweb
0.0.64
0.0.66
0.0.65
0.0.64
0.0.63
0.0.62
0.0.61
0.0.60
0.0.59
0.0.58
0.0.56
0.0.55
0.0.54
0.0.53
0.0.51
0.0.50
0.0.49
0.0.48
0.0.47
0.0.46
0.0.42
0.0.41
0.0.40
0.0.39
0.0.38
0.0.37
0.0.36
0.0.35
0.0.34
0.0.33
0.0.32
0.0.31
0.0.30
0.0.29
0.0.28
0.0.27
0.0.26
0.0.25
0.0.24
0.0.23
0.0.22
0.0.21
0.0.20
0.0.19
0.0.17
0.0.16
0.0.15
0.0.14
0.0.13
0.0.12
0.0.10
0.0.9
0.0.8
0.0.7
0.0.6
0.0.5
0.0.3
0.0.2
0.0.1
Collection of common IndieWeb utilites like authorship resolution, Webmention, post type discovery and IndieAuth.
Current section
Files
Jump to
Current section
Files
lib/indieweb/auth/token.ex
defmodule IndieWeb.Auth.Token do
@moduledoc "Manages the token lifecycle for IndieAuth."
alias IndieWeb.{Auth.Code, Auth.Scope, Auth.Scope, Http, Auth.DefaultTokenAdapter}
defmodule Adapter do
@moduledoc "Provides an abstraction regarding code actions for IndieAuth."
@callback generate(client_id :: binary(), scope :: binary(), options :: keyword()) :: binary()
@callback info(token :: binary(), options :: keyword()) :: nil | {:error, any()} | map()
@callback delete(token :: binary(), options :: keyword()) :: :ok
end
@spec generate(binary(), binary(), binary(), keyword()) :: {:ok, binary()} | {:error, atom(), any()}
def generate(code, client_id, redirect_uri, options \\ []) do
with(
scope when is_list(scope) and scope != [] <- Scope.get(code, options),
scope_str <- Scope.to_string(scope),
:ok <-
(fn ->
case Code.verify(code, client_id, redirect_uri, options) do
{:ok, %{"scope" => ^scope_str}} -> :ok
{:ok, %{"scope" => scope}} -> {:error, {:scope_mismatch, scope: scope}}
end
end).()
) do
Code.destroy(code, options)
adapter(options).generate(client_id, scope_str)
else
nil -> {:error, :token_generation_failure, reason: :missing_scope}
{:error, reason} -> {:error, :token_generation_failure, reason: reason}
end
end
def delete(token, options \\ []) do
adapter(options).delete(token, options)
end
@spec info_for(binary(), keyword()) :: nil | map() | {:error, any()}
def info_for(token, options \\ []) do
adapter(options).info(token, options)
end
@doc "Verifies if the provided token is valid."
@spec verify(binary(), binary()) :: {:ok, map()} | {:error, any()}
def verify(endpoint, token) do
case Http.get(endpoint,
headers: [
{"Authorization", "Bearer #{token}"},
{"Accept", "application/json"}
]
) do
{:ok, %Http.Response{body: body, code: 200}} -> Jason.decode(body)
{:ok, %Http.Response{} = _resp} -> {:error, :unauthorized}
{:error, _} = error -> error
end
end
@doc "Revokes the provided token against the endpoint."
@spec revoke(binary(), binary()) :: :ok | :revocation_failed
def revoke(endpoint, token) do
case Http.post_encoded(endpoint,
headers: [{"Accept", "application/json"}],
body: %{action: :revoke, token: token}
) do
{:ok, %Http.Response{code: 200}} -> :ok
_ -> :revocation_failed
end
end
defp adapter(options) do
options
|> Keyword.get(:adapters, [])
|> Keyword.get(:token, DefaultTokenAdapter)
end
end