View Source Kloak (kloak v0.2.1)
This module is as a simple wrapper around OAuth2
, which helps building a valid configuration for authorizing with a Keycloak server.
Examples
Phoenix controller
@doc "Login controller action which redirects to Keycloak for authentication."
def login(conn, _) do
with {:ok, client} <- Kloak.Client.new(),
{:ok, nonce} <- Kloak.generate_nonce(),
{:ok, redirect_url} <- Kloak.authorize_url(client, scope: "openid", state: nonce, redirect_uri: url(~p"/auth/callback")) do
conn
|> Kloak.put_oidc_state(nonce)
|> redirect(external: redirect_url)
end
end
@doc "Callback controller action which is called when a users is redirected from Keycloak."
def callback(conn, %{"code" => code, "state" => state}) do
with {:ok, true} <- Kloak.verify_oidc_state(conn, state),
{:ok, client} <- Kloak.Client.new(),
{:ok, token} <- Kloak.get_token(client, code: code, redirect_uri: url(~p"/auth/callback")),
{:ok, client} <- Kloak.Client.new(token: token),
{:ok, user_information} <- Kloak.user_information(client) do
# Do something with the user information
IO.inspect(user_information)
# Authentication was successful
conn
|> put_session(:token, token)
|> put_flash(:info, gettext("You have successfully logged in."))
|> redirect(to: ~p"/dashboard")
end
end
Summary
Functions
Build the autorization URL, which is required in the authentication flow. This built URL is used for redirecting to Keycloak.
Delete the OpenID Connect state from the session of the current user.
Generate a unique, secure random nonce of the given size.
Try to get the access token from Keycloak with the given, preconfigured OAuth2.Client
.
Put the OpenID Connect state into the session in order to be able to verify that an authentication is requested by the actual user.
Fetches the user information of the authenticated user from the Keycloak userinfo endpoint.
The passed OAuth2.Client
must be properly configured and authorized to perform this action.
Verify the OpenID Connect state from the redirect with the state stored in the session of the current user.
Functions
@spec authorize_url( OAuth2.Client.t(), keyword() ) :: {:ok, binary()} | {:error, binary()}
Build the autorization URL, which is required in the authentication flow. This built URL is used for redirecting to Keycloak.
Examples
iex> authorize_url(%OAuth2.Client{...})
{:ok, "https://localhost:4000/..."}
iex> authorize_url(%OAuth2.Client{...})
{:error, "Building the authorization URL failed with an invalid URL"}
iex> authorize_url(%OAuth2.Client{...})
{:error, "Building the authorization URL failed with an unknown error"}
@spec delete_oidc_state(conn :: Plug.Conn.t(), oidc_state_key :: atom()) :: Plug.Conn.t()
Delete the OpenID Connect state from the session of the current user.
Examples
iex> delete_oidc_state(%Plug.Conn{})
%Plug.Conn{...}
iex> delete_oidc_state(%Plug.Conn{}, :extra_oidc_state_key)
%Plug.Conn{...}
@spec generate_nonce(non_neg_integer()) :: {:ok, binary()} | {:error, binary()}
Generate a unique, secure random nonce of the given size.
Examples
iex> generate_nonce()
{:ok, "aas7d8ads8789asd7981aas7d8ads87d"}
iex> generate_nonce(8)
{:ok, "aas7d8ad"}
iex> generate_nonce(8)
{:error, "Generating nonce failed with an invalid result"}
iex> generate_nonce(nil)
{:error, "Generating nonce failed due to an invalid given size"}
@spec get_token(OAuth2.Client.t(), keyword(), keyword(), keyword()) :: {:ok, OAuth2.AccessToken.t()} | {:error, binary()}
Try to get the access token from Keycloak with the given, preconfigured OAuth2.Client
.
Examples
iex> get_token(%OAuth2.Client{...})
{:ok, %OAuth2.AccessToken{...}}
iex> get_token(%OAuth2.Client{...})
{:error, "Getting the access token from Keycloak failed"}
@spec put_oidc_state( conn :: Plug.Conn.t(), oidc_state :: binary(), oidc_state_key :: atom() ) :: Plug.Conn.t()
Put the OpenID Connect state into the session in order to be able to verify that an authentication is requested by the actual user.
Examples
iex> put_oidc_state(%Plug.Conn{}, "somestate")
%Plug.Conn{...}
iex> put_oidc_state(%Plug.Conn{}, "somestate", :extra_oidc_state_key)
%Plug.Conn{...}
@spec user_information(OAuth2.Client.t()) :: {:ok, map()} | {:error, binary()}
Fetches the user information of the authenticated user from the Keycloak userinfo endpoint.
The passed OAuth2.Client
must be properly configured and authorized to perform this action.
Examples
iex> user_information(valid_client)
{:ok, %{"given_name" => "John", ...}}
iex> user_information(invalid_client)
{:error, "Retriving user information from Keycloak failed with an error"}
iex> user_information(invalid_client)
{:error, "Retriving user information failed due to an invalid realm configuration"}
verify_oidc_state(conn, oidc_state, oidc_state_key \\ :oidc_state)
View Source@spec verify_oidc_state( conn :: Plug.Conn.t(), oidc_state :: binary(), oidc_state_key :: atom() ) :: {:ok, boolean()} | {:error, binary()}
Verify the OpenID Connect state from the redirect with the state stored in the session of the current user.
Examples
iex> verify_oidc_state(%Plug.Conn{}, "statefromredirection")
{:ok, true}
iex> verify_oidc_state(%Plug.Conn{}, "invalidstatefromredirection")
{:ok, false}
iex> verify_oidc_state(%Plug.Conn{}, "somestate", :extra_oidc_state_key)
{:error, "Unable to retrieve OIDC state from session"}
iex> verify_oidc_state(%Plug.Conn{}, nil, nil)
{:error, "Unable to verify invalid OIDC state with invalid attributes"}