defmodule Ueberauth.Strategy.WorkOS.OAuth do @moduledoc """ Implementation of an OAuth 2.0 strategy for WorkOS Single Sign-On > #### Note {:.info} > This module is not intended to be called or configured directly. Please see > `Ueberauth.Strategy.WorkOS` for all relevant configuration and documentation. ## Configuration This module uses the configuration defined in `Ueberauth.Strategy.WorkOS`. Unlike other Ueberauth strategies, there is no need to define application environment variables for this module. """ use OAuth2.Strategy @defaults [ authorize_url: "https://api.workos.com/sso/authorize", headers: [{"user-agent", "ueberauth_workos"}], site: "https://api.workos.com", strategy: __MODULE__, token_url: "https://api.workos.com/sso/token" ] # # Ueberauth Strategy Helpers # @doc """ Construct a client for requests to the WorkOS API ## Options This function accepts the same options as `OAuth2.Client.new/1`, including a `redirect_uri`. All options are collected and merged in this way: * Options passed directly to this function have the highest precedence, overriding all others. * Options configured with `Ueberauth.Strategy.WorkOS` have next-highest priority. * There are default values for `authorize_url`, `headers`, `site`, and `token_url`. OAuth2 will use the same JSON serialization library as returned by `Ueberauth.json_library/0`. """ @spec client(keyword) :: OAuth2.Client.t() def client(opts \\ []) do config = Application.get_env(:ueberauth, Ueberauth.Strategy.WorkOS) || [] client_opts = @defaults |> Keyword.merge(config) |> Keyword.merge(opts) |> check_credential(:client_id) |> check_credential(:api_key, :client_secret) json_library = Ueberauth.json_library() client_opts |> OAuth2.Client.new() |> OAuth2.Client.put_serializer("application/json", json_library) end @spec check_credential(keyword, atom, atom) :: keyword defp check_credential(config, key, rename_to \\ nil) do validate_key_exists(config, key) case Keyword.get(config, key) do value when is_binary(value) -> if rename_to do config |> Keyword.delete(key) |> Keyword.put(rename_to, value) else config end {:system, env_key} -> case System.get_env(env_key) do nil -> raise """ Missing environment variable #{inspect(env_key)} in configuration for Ueberauth.Strategy.WorkOS This variable is configured for the #{inspect(key)} key. """ value -> new_key_name = rename_to || key Keyword.put(config, new_key_name, value) end end end @spec validate_key_exists(keyword, atom) :: keyword | no_return defp validate_key_exists(config, key) when is_list(config) do unless Keyword.has_key?(config, key) do raise """ Missing required key #{inspect(key)} in configuration for Ueberauth.Strategy.WorkOS Example configuration: config :ueberauth, Ueberauth, providers: [ workos: {Ueberauth.Strategy.WorkOS, [ api_key: "...", client_id: "..." ]} ] OR config :ueberauth, Ueberauth.Strategy.WorkOS, api_key: "...", client_id: "..." """ end config end @doc "Get the authorization URL used during the request phase of Ueberauth" @spec authorize_url!(keyword, keyword) :: String.t() def authorize_url!(params \\ [], opts \\ []) do opts |> client() |> OAuth2.Client.authorize_url!(params) end # # OAuth2 Strategy Callbacks # @doc false @impl OAuth2.Strategy def authorize_url(client, params) do OAuth2.Strategy.AuthCode.authorize_url(client, params) end @doc false @impl OAuth2.Strategy def get_token(client, params, headers) do client |> put_header("Accept", "application/json") |> put_param(:client_secret, client.client_secret) |> OAuth2.Strategy.AuthCode.get_token(params, headers) end end