-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathelixir_auth_github.ex
85 lines (71 loc) · 2.64 KB
/
elixir_auth_github.ex
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
defmodule ElixirAuthGithub do
@moduledoc """
ElixirAuthGithub is an Elixir package that handles all your GitHub OAuth needs
so you can add "Sign in with GitHub" to any Elixir/Phoenix App.
For all setup details, please see: https://github.com/dwyl/elixir-auth-github
"""
@github_url "https://github.com/login/oauth/"
@github_auth_url @github_url <> "access_token?"
@httpoison Application.get_env(:elixir_auth_github, :httpoison) || HTTPoison
@doc """
`login_url/0` returns a `String` URL to be used as the initial OAuth redirect.
Requires `GITHUB_CLIENT_ID` environment variable to be set.
See step 2 of setup instructions.
"""
def login_url do
client_id = System.get_env("GITHUB_CLIENT_ID")
@github_url <> "authorize?client_id=#{client_id}"
end
@doc """
Identical to `login_url/0` except with an additional state property
appended to the URL.
"""
def login_url(state) do
login_url() <> "&state=#{state}"
end
@doc """
login_url_with_scope/1 takes a list of GitHub auth scopes to add to the url.
Returns `String` URL.
"""
def login_url_with_scope(scopes) do
login_url() <> "&scope=#{Enum.join(scopes, "%20")}"
end
@doc """
When called with a valid OAuth callback code, `github_auth/1` makes a number of
authentication requests to GitHub and returns a tuple with `:ok` and a map with
GitHub user details and an access_token.
Bad authentication codes will return a tuple with `:error` and an error map.
"""
def github_auth(code) do
%{"client_id" => System.get_env("GITHUB_CLIENT_ID"),
"client_secret" => System.get_env("GITHUB_CLIENT_SECRET"),
"code" => code}
|> URI.encode_query
|> (&(@httpoison.post!(@github_auth_url <> &1, ""))).()
|> Map.get(:body)
|> URI.decode_query
|> check_authenticated
end
defp check_authenticated(%{"access_token" => access_token}) do
access_token
|> get_user_details
end
defp check_authenticated(error), do: {:error, error}
defp get_user_details(access_token) do
@httpoison.get!("https://api.github.com/user", [
{"User-Agent", "elixir-practice"},
{"Authorization", "token #{access_token}"}
])
|> Map.get(:body)
|> Poison.decode!
|> set_user_details(access_token)
end
defp set_user_details(%{"login" => _name} = user, access_token) do
user = Map.put(user, "access_token", access_token)
# transform map with keys as strings into keys as atoms!
atom_key_map = for {key, val} <- user, into: %{},
do: {String.to_atom(key), val}
{:ok, atom_key_map}
end # https://stackoverflow.com/questions/31990134
defp set_user_details(error, _token), do: {:error, error}
end