diff --git a/lib/phoenix_oauth2_provider/views/authorization_view.ex b/lib/phoenix_oauth2_provider/views/authorization_view.ex index 8d64c0e..96e5203 100644 --- a/lib/phoenix_oauth2_provider/views/authorization_view.ex +++ b/lib/phoenix_oauth2_provider/views/authorization_view.ex @@ -30,6 +30,12 @@ defmodule PhoenixOauth2Provider.AuthorizationView do " /> " /> " /> + <%%= if @params["code_challenge"] do %> + " /> + <%% end %> + <%%= if @params["code_challenge_method"] do %> + " /> + <%% end %> <%%= submit "Authorize" %> <%% end %> <%%= form_tag Routes.oauth_authorization_path(@conn, :delete), method: :delete do %> @@ -38,6 +44,12 @@ defmodule PhoenixOauth2Provider.AuthorizationView do " /> " /> " /> + <%%= if @params["code_challenge"] do %> + " /> + <%% end %> + <%%= if @params["code_challenge_method"] do %> + " /> + <%% end %> <%%= submit "Deny" %> <%% end %> diff --git a/test/phoenix_oauth2_provider/controllers/authorization_controller_pkce_test.exs b/test/phoenix_oauth2_provider/controllers/authorization_controller_pkce_test.exs new file mode 100644 index 0000000..0954ddd --- /dev/null +++ b/test/phoenix_oauth2_provider/controllers/authorization_controller_pkce_test.exs @@ -0,0 +1,79 @@ +defmodule PhoenixOauth2Provider.AuthorizationControllerPkceTest do + use PhoenixOauth2Provider.ConnCase + + alias Dummy.{OauthAccessGrants.OauthAccessGrant, Repo} + alias PhoenixOauth2Provider.Test.Fixtures + alias Plug.Conn + + @code_challenge "1234567890123456789012345678900123456789012345" + + setup_all %{} do + new_conf = Application.get_env(:phoenix_oauth2_provider, ExOauth2Provider) ++ [use_pkce: true] + Application.put_env(:phoenix_oauth2_provider, ExOauth2Provider, new_conf) + + :ok + end + + setup %{conn: conn} do + user = Fixtures.user() + conn = Conn.assign(conn, :current_test_user, user) + application = Fixtures.application(%{user: user}) + {:ok, conn: conn, user: user, application: application} + end + + test "create/2 redirects with code_challenge, code_challenge_method", %{ + conn: conn, + user: %{id: user_id}, + application: application + } do + request = valid_request(application, @code_challenge, "plain") + conn = post(conn, Routes.oauth_authorization_path(conn, :create, request)) + assert redirected_to(conn) == "https://example.com?code=#{last_grant_token()}" + + assert %{ + resource_owner_id: ^user_id, + code_challenge: @code_challenge, + code_challenge_method: "plain" + } = last_grant() + end + + test "create/2 redirects with code_challenge", %{ + conn: conn, + user: %{id: user_id}, + application: application + } do + request = valid_request(application, @code_challenge) + conn = post(conn, Routes.oauth_authorization_path(conn, :create, request)) + assert redirected_to(conn) == "https://example.com?code=#{last_grant_token()}" + + assert %{ + resource_owner_id: ^user_id, + code_challenge: @code_challenge, + code_challenge_method: "plain" + } = last_grant() + end + + test "delete/2 redirects with pkce params", %{conn: conn, application: application} do + conn = delete( + conn, Routes.oauth_authorization_path(conn, :delete, valid_request(application, @code_challenge, "plain")) + ) + + assert redirected_to(conn) == + "https://example.com?error=access_denied&error_description=The+resource+owner+or+authorization+server+denied+the+request." + end + + defp valid_request(%{uid: uid}, code_challenge), + do: %{client_id: uid, response_type: "code", code_challenge: code_challenge} + + defp valid_request(application, code_challenge, code_challenge_method), + do: + Map.merge(valid_request(application, code_challenge), %{"code_challenge_method" => code_challenge_method}) + + defp last_grant do + OauthAccessGrant + |> Repo.all() + |> List.last() + end + + defp last_grant_token, do: last_grant().token +end