Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for userinfo endpoint #39

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions lib/openid_connect.ex
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,25 @@ defmodule OpenIDConnect do
end
end

@spec fetch_userinfo(provider, String.t(), name) :: success(map) | error(:fetch_userinfo)
@doc """
Fetches the information that the user has consented to share
"""
def fetch_userinfo(provider, access_token, name \\ :openid_connect) do
uri = userinfo_uri(provider, name)
headers = [{"Authorization", "Bearer #{access_token}"}]

with {:ok, %HTTPoison.Response{status_code: status_code} = resp} when status_code in 200..299 <-
http_client().get(uri, headers, http_client_options()),
{:ok, json} <- Jason.decode(resp.body),
{:ok, json} <- assert_json(json) do
{:ok, json}
else
{:ok, resp} -> {:error, :fetch_tokens, resp}
{:error, reason} -> {:error, :fetch_tokens, reason}
end
end

@spec update_documents(list) :: success(documents) | error(:update_documents)
@doc """
Requests updated documents from the provider
Expand Down Expand Up @@ -282,6 +301,10 @@ defmodule OpenIDConnect do
Map.get(discovery_document(provider, name), "token_endpoint")
end

defp userinfo_uri(provider, name) do
Map.get(discovery_document(provider, name), "userinfo_endpoint")
end

defp client_id(config) do
Keyword.get(config, :client_id)
end
Expand Down
32 changes: 32 additions & 0 deletions test/fixtures/google/userinfo.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
%HTTPoison.Response{
body: %{
"sub" => "353690423699814251281",
"name" => "Ada Lovelace",
"given_name" => "Ada",
"family_name" => "Lovelace",
"picture" =>
"https://lh3.googleusercontent.com/-XdUIqdMkCWA/AAAAAAAAAAI/AAAAAAAAAAA/4252rscbv5M/photo.jpg",
"email" => "[email protected]",
"email_verified" => true,
"locale" => "en"
},
headers: [
{"Date", "Thu, 17 Dec 2020 14:29:16 GMT"},
{"Cache-Control", "no-cache, no-store, max-age=0, must-revalidate"},
{"Expires", "Mon, 01 Jan 1990 00:00:00 GMT"},
{"Pragma", "no-cache"},
{"Content-Type", "application/json; charset=utf-8"},
{"Vary", "X-Origin"},
{"Vary", "Referer"},
{"Server", "ESF"},
{"X-XSS-Protection", "0"},
{"X-Frame-Options", "SAMEORIGIN"},
{"X-Content-Type-Options", "nosniff"},
{"Alt-Svc",
"h3-29=\":443\"; ma=2592000,h3-T051=\":443\"; ma=2592000,h3-Q050=\":443\"; ma=2592000,h3-Q046=\":443\"; ma=2592000,h3-Q043=\":443\"; ma=2592000,quic=\":443\"; ma=2592000; v=\"46,43\""},
{"Accept-Ranges", "none"},
{"Vary", "Origin,Accept-Encoding"},
{"Transfer-Encoding", "chunked"}
],
status_code: 200
}
30 changes: 30 additions & 0 deletions test/openid_connect_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ defmodule OpenIDConnectTest do

@google_document Fixtures.load(:google, :discovery_document)
@google_certs Fixtures.load(:google, :certs)
@google_userinfo Fixtures.load(:google, :userinfo)

alias OpenIDConnect.{HTTPClientMock, MockWorker}

Expand Down Expand Up @@ -526,6 +527,35 @@ defmodule OpenIDConnectTest do
end
end

describe "fetch userinfo" do
test "when successful" do
{:ok, pid} = GenServer.start_link(MockWorker, [], name: :openid_connect)

access_token = "mF_9.B5f-4.1JqM"
headers = [{"Authorization", "Bearer #{access_token}"}]

expected_userinfo =
@google_userinfo
|> elem(1)
|> Map.get(:body)
|> Jason.decode!()

try do
expect(HTTPClientMock, :get, fn "https://www.googleapis.com/oauth2/v3/userinfo",
^headers,
_opts ->
@google_userinfo
end)

{:ok, body} = OpenIDConnect.fetch_userinfo(:google, access_token)

assert expected_userinfo == body
after
GenServer.stop(pid)
end
end
end

defp set_jose_json_lib(_) do
JOSE.json_module(JasonEncoder)
[]
Expand Down