Packages
boruta
1.0.1
3.0.0-beta.4
3.0.0-beta.3
3.0.0-beta.2
3.0.0-beta.1
2.3.6
2.3.5
2.3.4
2.3.3
2.3.2
2.3.1
2.3.0
2.2.2
2.2.1
2.2.0
2.1.5
2.1.4
2.1.3
2.1.2
2.1.1
2.1.0
2.0.1
2.0.0
2.0.0-rc.1
2.0.0-rc.0
1.2.1
1.2.0
1.1.0
1.0.3
1.0.2
1.0.1
1.0.0
1.0.0-rc.3
1.0.0-rc.2
1.0.0-rc.1
1.0.0-rc.0
0.2.1
0.2.0
0.1.1
0.1.0
0.1.0-rc.5
0.1.0-rc.4
0.1.0-rc.3
0.1.0-rc.2
0.1.0-rc.1
Core of an OAuth/OpenID Connect provider enabling authorization in your applications.
Current section
Files
Jump to
Current section
Files
lib/boruta/adapters/ecto/schemas/token.ex
defmodule Boruta.Ecto.Token do
@moduledoc false
use Ecto.Schema
import Ecto.Changeset
import Boruta.Config,
only: [
token_generator: 0
]
alias Boruta.Ecto.Client
alias Boruta.Oauth
@type t :: %__MODULE__{
type: String.t(),
value: String.t(),
state: String.t(),
scope: String.t(),
redirect_uri: String.t(),
expires_at: integer(),
client: Client.t(),
sub: String.t(),
revoked_at: DateTime.t()
}
@primary_key {:id, :binary_id, autogenerate: true}
@foreign_key_type :binary_id
@timestamps_opts type: :utc_datetime_usec
schema "tokens" do
field(:type, :string)
field(:value, :string)
field(:refresh_token, :string)
field(:state, :string)
field(:scope, :string)
field(:redirect_uri, :string)
field(:expires_at, :integer)
field(:revoked_at, :utc_datetime_usec)
field(:code_challenge, :string, virtual: true)
field(:code_challenge_hash, :string)
field(:code_challenge_method, :string, default: "plain")
field(:access_token_ttl, :integer, virtual: true)
field(:authorization_code_ttl, :integer, virtual: true)
belongs_to(:client, Client)
field(:sub, :string)
timestamps()
end
@doc false
def changeset(token, attrs) do
token
|> cast(attrs, [:client_id, :redirect_uri, :sub, :state, :scope, :access_token_ttl])
|> validate_required([:access_token_ttl])
|> validate_required([:client_id])
|> foreign_key_constraint(:client_id)
|> put_change(:type, "access_token")
|> put_value()
|> put_expires_at()
end
@doc false
def changeset_with_refresh_token(token, attrs) do
token
|> cast(attrs, [:access_token_ttl, :client_id, :redirect_uri, :sub, :state, :scope])
|> validate_required([:access_token_ttl, :client_id])
|> foreign_key_constraint(:client_id)
|> put_change(:type, "access_token")
|> put_value()
|> put_refresh_token()
|> put_expires_at()
end
@doc false
def code_changeset(token, attrs) do
token
|> cast(attrs, [
:authorization_code_ttl,
:client_id,
:sub,
:redirect_uri,
:state,
:scope
])
|> validate_required([:authorization_code_ttl, :client_id, :sub, :redirect_uri])
|> foreign_key_constraint(:client_id)
|> put_change(:type, "code")
|> put_value()
|> put_code_expires_at()
end
def pkce_code_changeset(token, attrs) do
token
|> cast(attrs, [
:authorization_code_ttl,
:client_id,
:sub,
:redirect_uri,
:state,
:scope,
:code_challenge,
:code_challenge_method
])
|> validate_required([
:authorization_code_ttl,
:client_id,
:sub,
:redirect_uri,
:code_challenge
])
|> foreign_key_constraint(:client_id)
|> put_change(:type, "code")
|> put_value()
|> put_code_expires_at()
|> put_code_challenge_method()
|> encrypt_code_challenge()
end
defp put_value(%Ecto.Changeset{data: data, changes: changes} = changeset) do
put_change(
changeset,
:value,
token_generator().generate(:access_token, struct(data, changes))
)
end
defp put_refresh_token(%Ecto.Changeset{data: data, changes: changes} = changeset) do
put_change(
changeset,
:refresh_token,
token_generator().generate(:refresh_token, struct(data, changes))
)
end
defp put_expires_at(changeset) do
{_type, access_token_ttl} = fetch_field(changeset, :access_token_ttl)
put_change(changeset, :expires_at, :os.system_time(:seconds) + access_token_ttl)
end
defp put_code_expires_at(changeset) do
{_type, authorization_code_ttl} = fetch_field(changeset, :authorization_code_ttl)
put_change(changeset, :expires_at, :os.system_time(:seconds) + authorization_code_ttl)
end
defp put_code_challenge_method(changeset) do
code_challenge_method = case get_field(changeset, :code_challenge_method) do
nil -> "plain"
code_challenge_method -> code_challenge_method
end
put_change(changeset, :code_challenge_method, code_challenge_method)
end
defp encrypt_code_challenge(%Ecto.Changeset{valid?: true} = changeset) do
changeset
|> put_change(
:code_challenge_hash,
changeset |> get_field(:code_challenge, "") |> Oauth.Token.hash()
)
end
defp encrypt_code_challenge(changeset), do: changeset
end