defmodule NolaWeb.OpenIdController do use NolaWeb, :controller plug(NolaWeb.ContextPlug, restrict: :public) require Logger def login(conn, _) do url = OAuth2.Client.authorize_url!(new_client(), scope: "openid", state: Base.url_encode64(:crypto.strong_rand_bytes(32), padding: false) ) redirect(conn, external: url) end def callback(conn, %{"error" => error_code, "error_description" => error}) do Logger.warn("OpenId error: #{error_code} #{error}") render(conn, "error.html", error: error) end def callback(conn, %{"code" => code, "state" => state}) do with client = %{token: %OAuth2.AccessToken{access_token: json}} = OAuth2.Client.get_token!(new_client(), state: state, code: code), {:ok, %{"access_token" => token}} <- Jason.decode(json), client = %OAuth2.Client{client | token: %OAuth2.AccessToken{access_token: token}}, {:ok, %OAuth2.Response{body: body}} <- OAuth2.Client.get(client, "/userinfo"), {:ok, %{"sub" => id, "preferred_username" => username}} <- Jason.decode(body) do if account = conn.assigns.account do # XXX: And oidc id not linked yet if !Nola.Account.get_meta(account, "identity-id") do Nola.Account.put_meta(account, "identity-id", id) end Nola.Account.put_meta(account, "identity-username", username) conn else conn end conn |> put_session(:oidc_id, id) |> put_flash(:info, "Logged in!") |> redirect(to: Routes.path(conn, "/")) else {:error, %OAuth2.Response{status_code: 401}} -> Logger.error("OpenID: Unauthorized token") render(conn, "error.html", error: "The token is invalid.") {:error, %OAuth2.Error{reason: reason}} -> Logger.error("Error: #{inspect(reason)}") render(conn, "error.html", error: reason) end end def callback(conn, _params) do render(conn, "error.html", error: "Unspecified error.") end defp new_client() do config = Application.get_env(:nola, :oidc) OAuth2.Client.new( strategy: OAuth2.Strategy.AuthCode, client_id: config[:client_id], client_secret: config[:client_secret], site: config[:base_url], authorize_url: config[:authorize_url], token_url: config[:token_url], redirect_uri: Routes.open_id_url(NolaWeb.Endpoint, :callback) ) end end