Skip to content
Closed
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
50 changes: 50 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,56 @@ case OAuth2.Client.get(client, "/user") do
end
```

### Hosted Domain

```elixir
# If you want to restrict the user to a specific Google Hosted domain you may initialize the client with `hd`.

defmodule Google do
use OAuth2.Strategy

alias OAuth2.Strategy.AuthCode

def client do
OAuth2.Client.new([
strategy: __MODULE__,
client_id: System.get_env("GOOGLE_CLIENT_ID"),
client_secret: System.get_env("GOOGLE_CLIENT_SECRET"),
redirect_uri: System.get_env("REDIRECT_URI"),
site: "https://accounts.google.com",
authorize_url: "https://accounts.google.com/o/oauth2/auth",
token_url: "https://accounts.google.com/o/oauth2/token",
hd: System.get_env("YOUR_HOSTED_DOMAIN")
])
end

def authorize_url!(params \\ []) do
OAuth2.Client.authorize_url!(client(), params)
end

def get_token!(params \\ [], headers \\ []) do
OAuth2.Client.get_token!(client(), params, headers)
end

# strategy callbacks

def authorize_url(client, params) do
AuthCode.authorize_url(client, params)
end

def get_token(client, params, headers) do
client
|> put_param(:client_secret, client.client_secret)
|> put_header("Accept", "application/json")
|> AuthCode.get_token(params, headers)
end
end

# Generate the authorization URL limited to the Hosted Domain and redirect the user to the provider.
Google.authorize_url!(client)
# => "https://accounts.google.com/o/oauth2/auth?client_id=GOOGLE_CLIENT_ID&hd=unbabel.com&redirect_uri=REDIRECT_URI&response_type=code"
```

## Examples

- [Authenticate with Github (OAuth2/Phoenix)](https://github.com/scrogson/oauth2_example)
Expand Down
2 changes: 1 addition & 1 deletion lib/oauth2.ex
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ defmodule OAuth2 do

#### Authorization Code Flow (AuthCode Strategy)

Initialize a client with your `client_id`, `client_secret`, and `site`.
Initialize a client with your `client_id`, `client_secret`, and `site`. Optionally, You may add `hd` to specify your hosted domain when using Google.

client = OAuth2.Client.new([
strategy: OAuth2.Strategy.AuthCode, # default strategy is AuthCode
Expand Down
12 changes: 10 additions & 2 deletions lib/oauth2/client.ex
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ defmodule OAuth2.Client do
@type token :: AccessToken.t | nil
@type token_method :: :post | :get | atom
@type token_url :: binary
@type hd :: binary

@type t :: %Client{
authorize_url: authorize_url,
Expand All @@ -60,7 +61,8 @@ defmodule OAuth2.Client do
strategy: strategy,
token: token,
token_method: token_method,
token_url: token_url
token_url: token_url,
hd: hd
}

defstruct authorize_url: "/oauth/authorize",
Expand All @@ -75,7 +77,8 @@ defmodule OAuth2.Client do
strategy: OAuth2.Strategy.AuthCode,
token: nil,
token_method: :post,
token_url: "/oauth/token"
token_url: "/oauth/token",
hd: ""

@doc """
Builds a new `OAuth2.Client` struct using the `opts` provided.
Expand All @@ -101,6 +104,7 @@ defmodule OAuth2.Client do
Defaults to `:post`
* `token_url` - absolute or relative URL path to the token endpoint.
Defaults to `"/oauth/token"`
* `hd` - hosted domain, should be provided only if the user belongs to a Google specific hosted domain.

## Example

Expand Down Expand Up @@ -147,6 +151,7 @@ defmodule OAuth2.Client do
convert to strings.
"""
@spec put_param(t, String.t | atom, any) :: t
def put_param(%Client{} = client, :hd, ""), do: client
def put_param(%Client{params: params} = client, key, value) do
%{client | params: Map.put(params, "#{key}", value)}
end
Expand Down Expand Up @@ -195,6 +200,9 @@ defmodule OAuth2.Client do

iex> OAuth2.Client.authorize_url!(%OAuth2.Client{})
"/oauth/authorize?client_id=&redirect_uri=&response_type=code"

iex> OAuth2.Client.authorize_url!(%OAuth2.Client{hd: "example.com"})
"/oauth/authorize?client_id=&hd=example.com&redirect_uri=&response_type=code"
"""
@spec authorize_url!(t, list) :: binary
def authorize_url!(%Client{} = client, params \\ []) do
Expand Down
1 change: 1 addition & 0 deletions lib/oauth2/strategy/auth_code.ex
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ defmodule OAuth2.Strategy.AuthCode do
|> put_param(:response_type, "code")
|> put_param(:client_id, client.client_id)
|> put_param(:redirect_uri, client.redirect_uri)
|> put_param(:hd, client.hd)
|> merge_params(params)
end

Expand Down
16 changes: 16 additions & 0 deletions test/oauth2/client_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,13 @@ defmodule OAuth2.ClientTest do

setup do
server = Bypass.open
client_with_hd = build_client(site: bypass_server(server), hd: "example.com")
client = build_client(site: bypass_server(server))
client_with_token = tokenize_client(client)
async_client = async_client(client)

{:ok, client: client,
client_with_hd: client_with_hd,
server: server,
client_with_token: client_with_token,
async_client: async_client}
Expand All @@ -30,6 +32,20 @@ defmodule OAuth2.ClientTest do
assert query["client_id"] == client.client_id
assert query["redirect_uri"] == client.redirect_uri
assert query["response_type"] == "code"
assert is_nil(query["hd"])
end

test "authorize_url! with hosted domain", %{client_with_hd: client, server: server} do
uri = URI.parse(authorize_url!(client))
assert "#{uri.scheme}://#{uri.host}:#{uri.port}" == client.site
assert uri.port == server.port
assert uri.path == "/oauth/authorize"

query = URI.decode_query(uri.query)
assert query["client_id"] == client.client_id
assert query["redirect_uri"] == client.redirect_uri
assert query["response_type"] == "code"
assert query["hd"] == "example.com"
end

test "get_token, get_token!", %{client: client, server: server} do
Expand Down
23 changes: 23 additions & 0 deletions test/oauth2_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@ defmodule OAuth2Test do
site: "https://api.github.com",
redirect_uri: "http://localhost/auth/callback")

@client_with_hd build_client(client_id: "abc123",
client_secret: "xyz987",
site: "https://api.github.com",
redirect_uri: "http://localhost/auth/callback",
hd: "github.com")

test "`new` delegates to `OAuth2.Client.new/1`" do
client = @client
assert client.strategy == OAuth2.Strategy.AuthCode
Expand All @@ -20,6 +26,23 @@ defmodule OAuth2Test do
assert client.params == %{}
assert client.headers == []
assert client.redirect_uri == "http://localhost/auth/callback"
assert client.hd == ""
end

test "`new` with hosted domain delegates to `OAuth2.Client.new/1`" do
client = @client_with_hd
assert client.strategy == OAuth2.Strategy.AuthCode
assert client.site == "https://api.github.com"
assert client.client_id == "abc123"
assert client.client_secret == "xyz987"
assert client.site == "https://api.github.com"
assert client.authorize_url == "/oauth/authorize"
assert client.token_url == "/oauth/token"
assert client.hd == "github.com"
assert client.token_method == :post
assert client.params == %{}
assert client.headers == []
assert client.redirect_uri == "http://localhost/auth/callback"
end
end