Current section
Files
Jump to
Current section
Files
lib/twitch_api/auth.ex
defmodule TwitchAPI.Auth do
@moduledoc """
Twitch API Auth (and struct).
Functions for managing your auth and tokens.
See: https://dev.twitch.tv/docs/authentication/getting-tokens-oauth
## Notes
* `Implicit` grant flow gives user access tokens. Expiry: I don't know yet.
* `Client Credentials` grant flow gives app access tokens that expire
in `5011271` seconds (~58 days).
* `Authorization Code` grant flow gives user access tokens that expires
in `14124` seconds (~4 hours).
* `Device Code` grant flow gives a user access token that expires in
`14820` seconds (~4 hours).
"""
require Logger
@type t :: %__MODULE__{
client_id: String.t(),
client_secret: String.t() | nil,
access_token: String.t() | nil,
refresh_token: String.t() | nil,
expires_at: DateTime.t() | nil
}
@derive Jason.Encoder
@derive {Inspect, only: [:client_id, :expires_at]}
@enforce_keys [:client_id]
defstruct [:client_id, :client_secret, :access_token, :refresh_token, :expires_at]
@doc """
Make a new `Auth` struct with a `client_id`.
## Example
iex> Auth.new("some-client-id")
%Auth{client_id: "some-client-id"}
"""
@spec new(client_id :: String.t()) :: t()
def new(client_id) when is_binary(client_id) do
%__MODULE__{client_id: client_id}
end
@doc """
Make a new `Auth` struct with a `client_id` and `client_secret`.
## Example
iex> Auth.new("some-client-id", "secretssss")
%Auth{client_id: "some-client-id", client_secret: "secretssss"}
"""
@spec new(client_id :: String.t(), client_secret :: String.t() | nil) :: t()
def new(client_id, client_secret) when is_binary(client_id) do
%__MODULE__{client_id: client_id, client_secret: client_secret}
end
@doc """
Make a new `Auth` struct with a `client_id`, `client_secret`, and `access_token`.
## Example
iex> Auth.new("some-client-id", "secretssss", "sometokenabc123")
%Auth{client_id: "some-client-id", client_secret: "secretssss", access_token: "sometokenabc123"}
"""
@spec new(
client_id :: String.t(),
client_secret :: String.t() | nil,
access_token :: String.t() | nil
) ::
t()
def new(client_id, client_secret, access_token) when is_binary(client_id) do
%__MODULE__{client_id: client_id, client_secret: client_secret, access_token: access_token}
end
@doc """
Make a new `Auth` struct with a `client_id`, `client_secret`, `access_token`, and `refresh_token`.
## Example
iex> Auth.new("some-client-id", "secretssss", "sometokenabc123", "somerefreshabc123")
%Auth{
client_id: "some-client-id",
client_secret: "secretssss",
access_token: "sometokenabc123",
refresh_token: "somerefreshabc123"
}
"""
@spec new(
client_id :: String.t(),
client_secret :: String.t() | nil,
access_token :: String.t() | nil,
refresh_token :: String.t() | nil
) ::
t()
def new(client_id, client_secret, access_token, refresh_token) when is_binary(client_id) do
%__MODULE__{
client_id: client_id,
client_secret: client_secret,
access_token: access_token,
refresh_token: refresh_token
}
end
@doc """
Add a `client_secret` to the `Auth` struct.
## Example
iex> auth = Auth.new("some-client-id")
iex> Auth.put_client_secret(auth, "secretssss")
%Auth{client_id: "some-client-id", client_secret: "secretssss"}
"""
@spec put_client_secret(t(), client_secret :: String.t() | nil) :: t()
def put_client_secret(%__MODULE__{} = auth, client_secret) do
struct(auth, %{client_secret: client_secret})
end
@doc """
Add an `access_token` to the `Auth` struct.
## Example
iex> auth = Auth.new("some-client-id")
iex> Auth.put_access_token(auth, "abc123")
%Auth{client_id: "some-client-id", access_token: "abc123"}
"""
@spec put_access_token(t(), access_token :: String.t() | nil) :: t()
def put_access_token(%__MODULE__{} = auth, access_token) do
struct(auth, %{access_token: access_token})
end
@doc """
Merge string params into `Auth` struct.
## Example
iex> auth = Auth.new("some-client-id")
iex> params = %{"access_token" => "abc123", "refresh_token" => "def456"}
iex> Auth.merge_string_params(auth, params)
%Auth{
client_id: "some-client-id",
access_token: "abc123",
refresh_token: "def456"
}
"""
@spec merge_string_params(t(), params :: %{String.t() => term()}) :: t()
def merge_string_params(%__MODULE__{} = auth, %{} = params) do
struct(auth, %{
access_token: params["access_token"],
expires_at: expires_in_to_datetime(params["expires_in"]),
refresh_token: params["refresh_token"]
})
end
@spec expires_in_to_datetime(nil | pos_integer()) :: nil | DateTime.t()
defp expires_in_to_datetime(nil), do: nil
defp expires_in_to_datetime(expires_in) when is_integer(expires_in) do
DateTime.utc_now() |> DateTime.add(expires_in, :second)
end
end