GithubHelp home page GithubHelp logo

oauth2's Introduction

OAuth2 (Client)

Build Status Coverage Status Module Version Hex Docs Total Download License Last Updated

An Elixir OAuth 2.0 Client Library.

Install

# mix.exs

defp deps do
  # Add the dependency
  [
    {:oauth2, "~> 2.0"},
    {:hackney, "~> 1.18"} # depending on what tesla adapter you use
  ]
end

Configure a serializer

This library can be configured to handle encoding and decoding requests and responses automatically based on the accept and/or content-type headers.

If you need to handle various MIME types, you can simply register serializers like so:

OAuth2.Client.put_serializer(client, "application/vnd.api+json", Jason)
OAuth2.Client.put_serializer(client, "application/xml", MyApp.Parsers.XML)

The modules are expected to export encode!/1 and decode!/1.

defmodule MyApp.Parsers.XML do
  def encode!(data), do: # ...
  def decode!(binary), do: # ...
end

Please see the documentation for OAuth2.Serializer for more details.

Configure a http client

The http client library used is tesla, the default adapter is Httpc, since it comes out of the box with every Erlang instance but you can easily change it to something better. You can configure another adaptor like this:

config :oauth2, adapter: Tesla.Adapter.Mint

You can also add your own tesla middleware:

config :oauth2, middleware: [
  Tesla.Middleware.Retry,
  {Tesla.Middleware.Fuse, name: :example}
]

Debug mode

Sometimes it's handy to see what's coming back from the response when getting a token. You can configure OAuth2 to output the response like so:

config :oauth2, debug: true

Usage

Current implemented strategies:

  • Authorization Code
  • Password
  • Client Credentials

Authorization Code Flow (AuthCode Strategy)

# Initialize a client with client_id, client_secret, site, and redirect_uri.
# The strategy option is optional as it defaults to `OAuth2.Strategy.AuthCode`.

client = OAuth2.Client.new([
  strategy: OAuth2.Strategy.AuthCode, #default
  client_id: "client_id",
  client_secret: "abc123",
  site: "https://auth.example.com",
  redirect_uri: "https://example.com/auth/callback"
])

# Generate the authorization URL and redirect the user to the provider.
OAuth2.Client.authorize_url!(client)
# => "https://auth.example.com/oauth/authorize?client_id=client_id&redirect_uri=https%3A%2F%2Fexample.com%2Fauth%2Fcallback&response_type=code"

# Use the authorization code returned from the provider to obtain an access token.
client = OAuth2.Client.get_token!(client, code: "someauthcode")

# Use the access token to make a request for resources
resource = OAuth2.Client.get!(client, "/api/resource").body

Client Credentials Flow

Getting an initial access token:

# Initializing a client with the strategy `OAuth2.Strategy.ClientCredentials`

client = OAuth2.Client.new([
  strategy: OAuth2.Strategy.ClientCredentials,
  client_id: "client_id",
  client_secret: "abc123",
  site: "https://auth.example.com"
])

# Request a token from with the newly created client
# Token will be stored inside the `%OAuth2.Client{}` struct (client.token)
client = OAuth2.Client.get_token!(client)

# client.token contains the `%OAuth2.AccessToken{}` struct

# raw access token
access_token = client.token.access_token

Refreshing an access token:

# raw refresh token - use a client with `OAuth2.Strategy.Refresh` for refreshing the token
refresh_token = client.token.refresh_token

refresh_client = OAuth2.Client.new([
  strategy: OAuth2.Strategy.Refresh,
  client_id: "client_id",
  client_secret: "abc123",
  site: "https://auth.example.com",
  params: %{"refresh_token" => refresh_token}
])

# refresh_client.token contains the `%OAuth2.AccessToken{}` struct again
refresh_client = OAuth2.Client.get_token!(refresh_client)

Write Your Own Strategy

Here's an example strategy for GitHub:

defmodule GitHub do
  use OAuth2.Strategy

  # Public API

  def client do
    OAuth2.Client.new([
      strategy: __MODULE__,
      client_id: System.get_env("GITHUB_CLIENT_ID"),
      client_secret: System.get_env("GITHUB_CLIENT_SECRET"),
      redirect_uri: "http://myapp.com/auth/callback",
      site: "https://api.github.com",
      authorize_url: "https://github.com/login/oauth/authorize",
      token_url: "https://github.com/login/oauth/access_token"
    ])
    |> OAuth2.Client.put_serializer("application/json", Jason)
  end

  def authorize_url! do
    OAuth2.Client.authorize_url!(client(), scope: "user,public_repo")
  end

  # you can pass options to the underlying http library via `opts` parameter
  def get_token!(params \\ [], headers \\ [], opts \\ []) do
    OAuth2.Client.get_token!(client(), params, headers, opts)
  end

  # Strategy Callbacks

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

  def get_token(client, params, headers) do
    client
    |> put_header("accept", "application/json")
    |> OAuth2.Strategy.AuthCode.get_token(params, headers)
  end
end

Here's how you'd use the example GitHub strategy:

Generate the authorize URL and redirect the client for authorization.

GitHub.authorize_url!

Capture the code in your callback route on your server and use it to obtain an access token.

client = GitHub.get_token!(code: code)

Use the access token to access desired resources.

user = OAuth2.Client.get!(client, "/user").body

# Or
case OAuth2.Client.get(client, "/user") do
  {:ok, %OAuth2.Response{body: user}} ->
    user
  {:error, %OAuth2.Response{status_code: 401, body: body}} ->
    Logger.error("Unauthorized token")
  {:error, %OAuth2.Error{reason: reason}} ->
    Logger.error("Error: #{inspect reason}")
end

Examples

License

The MIT License (MIT)

Copyright (c) 2015 Sonny Scroggin

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

oauth2's People

Contributors

clemensm avatar dejanstrbac avatar drewolson avatar giddie avatar glassbead0 avatar goofansu avatar jeffutter avatar kianmeng avatar mgamini avatar nessamurmur avatar olafura avatar optikfluffel avatar pavelgnom avatar pedrosnk avatar quinnwilton avatar rossjones avatar ryansiu1995 avatar samterrell avatar scrogson avatar sheharyarn avatar simonalpha avatar slashmili avatar stephenmoloney avatar stevedomin avatar sumerman avatar tiagoefmoraes avatar tsubery avatar woylie avatar ymtszw avatar yordis avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

oauth2's Issues

Getting (OAuth2.Error) :closed when calling OAuth2.Client.get_token!/4

I've implemented the OAuth2 flow similar to the example. I'm connecting to Microsoft's Azure OAuth2 provider. My auth flow works in the development environment, but when I try to deploy it to our production environment with SSL, I get the following error when I reach the get_token portion of the code in which I try to request for an access_token.

Request: GET /auth/callback?code=<omitted>&session_state=<omitted>
** (exit) an exception was raised:
    ** (OAuth2.Error) :closed
        (oauth2) lib/oauth2/client.ex:248: OAuth2.Client.get_token!/4
        (arrow_directory) web/controllers/auth_controller.ex:33: ArrowDirectory.AuthController.callback/2
        (arrow_directory) web/controllers/auth_controller.ex:1: ArrowDirectory.AuthController.action/2
        (arrow_directory) web/controllers/auth_controller.ex:1: ArrowDirectory.AuthController.phoenix_controller_pipeline/2
        (arrow_directory) lib/arrow_directory/endpoint.ex:1: ArrowDirectory.Endpoint.instrument/4
        (arrow_directory) lib/phoenix/router.ex:261: ArrowDirectory.Router.dispatch/2
        (arrow_directory) web/router.ex:1: ArrowDirectory.Router.do_call/2
        (arrow_directory) lib/arrow_directory/endpoint.ex:1: ArrowDirectory.Endpoint.phoenix_pipeline/1
        (arrow_directory) lib/plug/debugger.ex:123: ArrowDirectory.Endpoint."call (overridable 3)"/2
        (arrow_directory) lib/arrow_directory/endpoint.ex:1: ArrowDirectory.Endpoint.call/2
        (plug) lib/plug/adapters/cowboy/handler.ex:15: Plug.Adapters.Cowboy.Handler.upgrade/4
        (cowboy) /opt/app/deps/cowboy/src/cowboy_protocol.erl:442: :cowboy_protocol.execute/4

What would cause the :closed exception?

Default json decoder (Poison) will not be used

Hi,
since I just spend more than an hour debugging why the authentication did not work.

I use Phoenix which already depends on Poison for JSOn decoding, so I assumed that this would be handled automatically. I also tried to explicitly adding it as a dependency for the application in mix.exs.
I now know that I have to manually configure the serializer in my config, but I would suggest to change this line to raise an error. Maybe not an error, but I think that just using the plain body leads to a lot of hidden bugs.

I would suggest that a missing decoder should not be ignored silently.

Client attempts to raise Response rather than Error when status in 400..599

When a server error type response is returned while running OAuth2.Client.get_token!(...), the content of the error tuple is an OAuth2.Response rather than OAuth2.Error causing an ArgumentError on the raise call.

Shouldn't the error response in OAuth2.Request.process_body(..) when is_binary(body) -- line 85 be wrapped in an error struct so as to be raisable? Perhaps the response can then be included in a meta field or something to get the specific contents of the error.

Doesn't always properly parse expires_at

I'm dealing with an API that returns the authorize request as such:

{ "access_token": "k8sbPR4is2C7ipTYgEbi8fe470mp", "refresh_token": "dQJiREMfaHhDBoGohIj7JEpIOYYk9Jif", "expires_in": "599" }

With expires_in as a string. With the existing code, here: https://github.com/scrogson/oauth2/blob/master/lib/oauth2/access_token.ex#L137 it would parse that into the integer 599, which is still not the correct value for expires_at. In this case, it would have to call expires_at again with the integer value to get the timestamp.

I'm not sure if having it call expires_at(int) at the end of the string version would break anything else or not.

Cannot skip url encode!

LinkedIn requires parenthesis to indicate parameters to return. OAuth2 encodes parenthesis to %28 and %29 which results in an error from LinkedIn. I found this code but it does not work. Why?

  def skip_url_encode_option, do: [hackney: [path_encode_fun: fn a -> a end]]

  def get_user_id!(client) do
    response = OAuth2.Client.get!(client, "/v1/people/~:(id)?format=json", [], skip_url_encode_option)
  end

:ssl_verify_hostname, "make" command failed

I'm trying to use oauth2 on OS X 10.11.4, but I cannot seem to get my dependencies straight. A mix deps.get, compile always results in

==> ssl_verify_hostname
rebar get-deps compile
make: rebar: No such file or directory
make: *** [erl] Error 1
==> cdcoll
** (Mix) Could not compile dependency :ssl_verify_hostname, "make" command failed.
You can recompile this dependency with "mix deps.compile ssl_verify_hostname",
update it with "mix deps.update ssl_verify_hostname" or clean it with "mix deps.clean
ssl_verify_hostname"

What am I missing here?

encode_query causing issues in OAuth.authorize_url! with params

Hello, I have an API that requires the URL parameters for scope to contain literal + and not %2B so when I call OAuth.authorize_url! it eventually calls URI.encode_query(client.params) here https://github.com/scrogson/oauth2/blob/master/lib/oauth2/client.ex#L181 which makes my scope params look like this scope=public%2Bread_user instead of what the API expects, i.e. this scope=public+read_user

Is there a way I'm not seeing to have it just pass the query params as is without calling URI.encode_query? Also in your opinion is this a bug in the API? Seems like it should be ok with both + and %2B in the url.

Thanks.

feature suggestion: auto refreshing access tokens

Hello,

I noticed there is implementation of refresh token and access token. For any long running access the users of the library would have to manually refresh tokens for providers that require it like Google. I think it makes sense to add some logic to automatically refresh expired tokens when making requests. For backward compatibility, we can off by default.
Let me know if you are interested in pull request.

OAuth.Client has not way to pass connection options around

We've been trying to implement authentication thru google oauth when we ran into CA-related issue. Basically Erlang's ssl does not know about CA that is used by Google APIs. Although one can pass all the necessary stuff down to hackney as opts thru Request (https://github.com/scrogson/oauth2/blob/master/lib/oauth2/request.ex#L9), this options are not exposed by OAuth.Client and are always [] by default (https://github.com/scrogson/oauth2/blob/master/lib/oauth2/client.ex#L146).

Release 0.9.2

Hello @scrogson,

Would you mind to release new version of oauth2 that contains fixes from #98? I'm struggling with the same issues that author was struggling at that time. Please ๐Ÿ˜ƒ .

Thanks a mill,
Bartek

"client secret cannot be empty" from Yahoo API

When I try to use OAuth2.Client.get_token!/2 with a %OAuth.Client{} containing the client_id and client_secret, it asks me to include the secret again? It seems like it's supposed to be able to just get that from the included client?

image

Not sending client_secret when getting token

I'm using oauth2 trying to connect to a Slack App. When get_token it is failing with:

"{"ok":false,"error":"bad_client_secret"}"

because Slack Access Token URL accepts the client_secret as param but oauth2 is not sending it.

A simple hack is to add the client_secret as param to the get_token function but is that correct?

Google Support?

Does this work with google? I am getting a missing required param :scope error when trying to use with google

Support streaming requests through HTTPoison

The underlying HTTP library, HTTPoison/Hackney, supports asynchronous requests but it seems that this library is not ready for them.

For example, in the case of response streaming:

 > OAuth2.AccessToken.get(token, "/1/Files/meocloud/output.m4a", [], [hackney: [:insecure, {:async, :once}]])
** (CaseClauseError) no case clause matching: {:ok, %HTTPoison.AsyncResponse{id: #Reference<0.0.2.3515>}}
        (oauth2) lib/oauth2/request.ex:16: OAuth2.Request.request/5
        (oauth2) lib/oauth2/access_token.ex:221: OAuth2.AccessToken.request/6
...

It would be nice to support both response and request streaming. Or at least be able to generate the correct headers for a request so that we could drive HTTPoison ourselves.

Doesn't seem to pass client_secret when getting a token

Not sure if it's actually needed, but passing client secret in params makes it work with google.

  def get_token!(params \\ [], headers \\ []) do
    OAuth2.Client.get_token!(client(), params ++ [{:client_secret, unquote(client_secret)}])
  end

Otherwise google returns

%{"error" => "invalid_request", "error_description" => "client_secret is missing."}

put_param encoding "+", how to do literal?

In the Twitch OAuth documentation, they have scopes separated by + signs. I am passing in put_param(:scope, "user_follows_edit+user_read") and it goes to scope=user_follows_edit%2Buser_read.

I need it to go to the literal + like scope=user_follows_edit+user_read. Is this possible currently?

get_token no client_secret in params

while using https://github.com/scrogson/oauth2_example (google auth) in

def get_token(%{token_method: method} = client, params \\ [], headers \\ [], opts \\ []) do
        {client, url} = token_url(client, params, headers)
        case Request.request(method, client, url, client.params, client.headers, opts) do

client.params =

%{"client_id" => "some_client_id",
  "code" => "5/codestring",
  "grant_type" => "authorization_code",
  "redirect_uri" => "http://localhost:4000/auth/google/callback"}

and this ends up throwing

%OAuth2.Response{body: %{"error" => "invalid_request",
    "error_description" => "client_secret is missing."},

just to test this theory (because I don't the inner workings) replacing the case line with

case Request.request(method, client, url, Map.put_new(client.params, "client_secret", client.client_secret), client.headers, opts) do

and it works.

Implement scope attribute to make it useable with Google

Hi Sonny,

I'm wondering if Google OAuth support is already on your roadmap and/or if you would welcome any help in the form of PRs?

From looking at a couple of libraries from other languages so far, implementing additional providers always seems a mess. Therefore I kind of like the approach that @hapijs took with bell, with this library could can define custom provider attributes in a map, thinking this would be fairly trivial to do in Elixir. Or would you prefer multiple different strategies implemented using your library as the base? (eg. https://github.com/zquestz/omniauth-google-oauth2)

What's your opinion on this?

Wrong Content-Type when calling token api

I'm using oauth2 library with:

oauth2: 0.9.0
hackney: 1.6.6
auth server: google
elixir --version
Erlang/OTP 19 [erts-8.2] [source] [64-bit] [smp:8:8] [async-threads:10] [hipe] [kernel-poll:false] [dtrace]

Elixir 1.4.0

Problem

When I try to get token with OAuth2.Client.get_token function I get failure from google OAuth server saying:

{"error" : "invalid_request"}

I debugged the request the we made from Elixir(hackney). it's like this:

accept: application/x-www-form-urlencoded
Content-Type: application/x-www-form-urlencoded, application/x-www-form-urlencoded, application/x-www-form-urlencoded, application/x-www-form-urlencoded
User-Agent: hackney/1.6.6
Host: 10.211.55.9:8000
Content-Length: 307

auth_scheme=request_body&client_id=XXXX&client_secret=SECCCC&code=CODE&grant_type=authorization_code&redirect_uri=https%3A%2F%2Flocalhost%3A4443%2F%2Fo%2Foauth%2Fcallback

And as you see Content-Type is somehow wrong.

I tried to call google oauth token with only one application/x-www-form-urlencoded and application/x-www-form-urlencoded, application/x-www-form-urlencoded, application/x-www-form-urlencoded, application/x-www-form-urlencoded and looks like google doesn't accept the latter as valid Content-Type

I even tried to change ouath2 code and only send one content-type:

    headers = [{"content-type", "application/x-www-form-urlencoded"}]
    case :hackney.request(method, url, headers, body, req_opts) do
      {:ok, ref} when is_reference(ref) ->

However still hackney was sending two content type:

Content-Type: application/x-www-form-urlencoded, application/x-www-form-urlencoded
User-Agent: hackney/1.6.6
Host: 10.211.55.9:8000
Content-Length: 307

Possible Fix

I tried to make a request using hackney 1.7.1 and looks like they fixed it on that version.

Is it possible to use new version of hackney in oauth2?

Respond with error when token is expired

Server headers:

[[{"Server", "nginx"}, {"Date", "Mon, 15 Jun 2015 17:43:08 GMT"}, {"Content-Length", "0"}, {"WWW-Authenticate", "Bearer realm="Service", error="invalid_token", error_description="The access token provided is invalid.""}, {"Age", "0"}, {"Connection", "keep-alive"}]

and body is blank. Stack trace:

** (Poison.SyntaxError) Unexpected end of input
lib/poison/parser.ex:54: Poison.Parser.parse!/2
lib/poison.ex:83: Poison.decode!/2
(oauth2) lib/oauth2/response.ex:35: OAuth2.Response.new/3
(oauth2) lib/oauth2/request.ex:43: OAuth2.Request.handle_request_body/3
(oauth2) lib/oauth2/access_token.ex:59: OAuth2.AccessToken.get/4

Google strategy not working because of response_type being sent when getting token

other_params: %{"error" => "invalid_request",
    "error_description" => "Parameter not allowed for this message type: response_type"}

I think because of this?

https://github.com/scrogson/oauth2/blob/master/lib/oauth2/strategy/auth_code.ex#L55

Not really sure tho 'cause no request actually happens here but does happen Client#get_token. ยฏ_(ใƒ„)_/ยฏ

Either way, how can I get rid of that param when making token request?

Subclass OAuth2.Request?

I'm wondering if there is any way to 'subclass' Oauth2.Request? I see that it uses HTTPoison.Base. I'm used to defining things like process_response_body with HTTPoison. Is there a way to do this with OAuth2?

Client.get_token! not parsing correctly for Yahoo API

After running OAuth2.Client.get_token!(client, code: "authcode", client_secret: "secret") I get back a%OAuth2.Client{}` struct with this inside:

token: %OAuth2.AccessToken{access_token: "{\"access_token\":\"ABC123A\",\"refresh_token\":\"ABC123B\",\"expires_in\":3600,\"token_type\":\"bearer\",\"xoauth_yahoo_guid\":\"ABC123C\"}"

I'm assuming that it parsed incorrectly, and all of those should be k/v inside of the AccessToken struct.

Changelog Request!

Please implement a changelog with deprecation notices in the future.

Thanks!

edit: Such as OAuth2.new to OAuth2.Client.new, and the access token response being returned instead of the body.

Shopify Strategy

I was following your example interface. I have hit a road block with Shopify Strategy. The code requires dynamic url for site, auth and token. Wondering how to incorporate that in the example?

Error: no match of right hand side value: :undefined

Hello! Fantastic library!
When I run your oauth2-example repository, everything works as expected. However, when I create a phoenix app from scratch and use the same code, I get the following error:

no match of right hand side value: :undefined

The code line this is on is as follows:

  def callback(conn, %{"code" => code}) do
    # Exchange an auth code for an access token
    client = Google.get_token!(code: code)
    # ....
  end

I've been trying everything to get this code to return, and nothing I do changes the error. I've changed client to :undefined, with no luck. Any help is appreciated!

expires doesn't work for facebook's oauth2

Referencing #59 @jeffutter
Facebook's oauth2 returns expires field as a number of seconds for the token to expire. The referenced PR made it this way that expires is interpreted as a timestamp on which the token will expire, not the number of seconds till the expiration. What is the basis for this decision?

Response from facebook is not parse properly

I am trying to upgrade ueberauth_facebook with the recent version of oauth2. However the response from facebook is in this format access_token=xxxx&expires=yyy and the headers is {"Content-Type", "text/plain; charset=UTF-8"}. I understand that there is a special decoding for "application/x-www-form-urlencoded" content type, and also there is some way to use serializer. Is there any way to include this serializer only when parsing response from facebook? because I think text/plain is quite general.

Or I am thinking to add something like so in Response decoder:

  defp decode_response_body(body, "text/plain") do
    case URI.decode_query(body) do
      %{"access_token" => _} = token -> token
      _ -> body
    end
  end

connection refused that never hits the server

Hi, I'm writing a ueberauth adapter for a custom rails application using doorkeeper.
I receive a "connection refused" during the first "handshake", when the provider hits my phoenix app redirect_uri with a code.
This is the client as in OAuth2.Client.get_token (all urls/codes are local obviously):

%OAuth2.Client{authorize_url: "http://localhost:3000/oauth/authorize",
 client_id: "9e382aae12f43dc6ae767e1b9a15de2f0b08837536109155f28c5392fbb58c34",
 client_secret: "a7c0d53db32622482c6aa2ddab159dbea8d9a37d2fd09518cc2e0ec85660ec4cs",
 headers: [{"content-type", "application/x-www-form-urlencoded"},
  {"accept", "application/json"}],
 params: %{"client_id" => "9e382aae12f43dc6ae767e1b9a15de2f0b08837536109155f28c5392fbb58c34",
   "client_secret" => "a7c0d53db32622482c6aa2ddab159dbea8d9a37d2fd09518cc2e0ec85660ec4cs",
   "code" => "5b0322bc66438b8ee6bce9c9ee7d24150c935784430d3dc421c9bba476ad7c9b",
   "grant_type" => "authorization_code",
   "redirect_uri" => "http://localhost:4000/auth/fitzdares/callback"},
 redirect_uri: "http://localhost:4000/auth/fitzdares/callback", ref: nil,
 request_opts: [], site: "http://localhost:3000",
 strategy: Ueberauth.Strategy.Fitzdares.OAuth, token: nil, token_method: :post,
 token_url: "http://localhost:3000/oauth/token"}

What is weird is that the POST never hits the provider, and I have no idea why. I guess I'm missing something very obvious on why the lib decides that connection has been refused, but for now I'm just losing a truckload of time without may ideas left on how to fix this.
Is there a way to have a better understanding of what's going on there? I enabled debug but I don't see much. Any suggestions?

Allow client to receive url as parameter

Im working on a strategy for a product where one can set up his/her own server, on a chosen location. If Im not overlooking something, at the time of writing this cant be easily done. I would like to pass additional information, like the URL to #client.

Please let me know what your opinion is on this.

Refresh is broken

When I refresh a token, the client incorrectly sends an authorization header (with the expired access_token) and an accepts header of application/x-www-form-urlencoded. The server I am talking to trips over the authorization header and refuses the refresh request.

As an aside, the Poison decoder subsequently trips over the HTML error message, probably because of the accepts header. For some reason I was unable to intercept and print the HTML response (I get a list of binaries like <<139, 8, 0, 0...>> that seems to be incomprehensible to Elixir. So this was brutally hard to debug.

Poison depedency

You have a dependency on Poison.
Probably up until now, since Phoenix was using poison, it was working fine. The new Phoenix use Jason. So you will either need to specify the Poison dependency or switch to using Jason.

Cut a new release

Is there any way a new release could be cut? I'm looking to publish something on hex.pm that uses this as a dep, but I need this commit: 3277a29

Thanks.

AccessToken in URL param instead of Authentication header

Hi, I'm playing around with the Soundcloud API and when doing a request they want me to put the AccessToken into an URL param like this https://api.soundcloud.com/me?oauth_token=A_VALID_TOKEN instead of putting it into the Authorization header as a Bearer token.
Could you give me a hint on what's the easiest way to get this going with your library?

Right now I'm simply doing this little, dirty workaround:

def get!(token, url) do
  access_token = Map.get(token, :access_token)
  url_with_token = url <> "?oauth_token=" <> access_token
  OAuth2.AccessToken.get!(token, url_with_token)
end

Thanks :)

Arguement error in `to_url`

I'm trying to put a simple Oauth link on the page, having followed the github example in the docs and come up against this error...

 ** (ArgumentError) argument error
        (oauth2) lib/oauth2/client.ex:391: OAuth2.Client.to_url/2
        (oauth2) lib/oauth2/client.ex:201: OAuth2.Client.authorize_url!/2

Checking out line 391 leads us to...

  defp to_url(client, endpoint) do
    endpoint = Map.get(client, endpoint)
    url = endpoint(client, endpoint) <> "?" <> URI.encode_query(client.params)
    {client, url}
  end

And putting in an IEx.pry shows that the endpoint(client, endpoint) function seems to be the culprit breaking here.

What's going on here? ๐Ÿ˜•

Weird error :noproc

I've copied and pasted the code from the demo app into my own app, and with both GitHub and Google I'm getting this error on the call to OAuth2.Client.get_token!(client(), params)

[error] #PID<0.422.0> running Dashboard.Endpoint terminated
Server: localhost:4000 (http)
Request: GET /auth/google/callback?code=4/8GTqlaN6ZY1GtJWJuUMxntdNgCL6Z3k3bC8GyJtVAUE
** (exit) an exception was raised:
    ** (OAuth2.Error) {:noproc, {:gen_server, :call, [:hackney_manager, {:new_request, #PID<0.422.0>, #Reference<0.0.1.2735>, {:client, :undefined, {:metrics_ng, :metrics_dummy}, :hackney_ssl_transport, 'accounts.google.com', 443, "accounts.google.com", [], nil, nil, nil, true, :hackney_pool, 5000, false, 5, false, 5, nil, nil, nil, :undefined, :start, nil, :normal, false, false, false, :undefined, false, nil, :waiting, nil, 4096, "", [], :undefined, nil, nil, nil, nil, :undefined, ...}}, :infinity]}}
        lib/oauth2/client.ex:171: OAuth2.Client.get_token!/4
        (dashboard) web/controllers/auth_controller.ex:27: Dashboard.AuthController.callback/2
        (dashboard) web/controllers/auth_controller.ex:1: Dashboard.AuthController.action/2
        (dashboard) web/controllers/auth_controller.ex:1: Dashboard.AuthController.phoenix_controller_pipeline/2
        (dashboard) lib/phoenix/router.ex:261: Dashboard.Router.dispatch/2
        (dashboard) web/router.ex:1: Dashboard.Router.do_call/2
        (dashboard) lib/dashboard/endpoint.ex:1: Dashboard.Endpoint.phoenix_pipeline/1
        (dashboard) lib/plug/debugger.ex:93: Dashboard.Endpoint."call (overridable 3)"/2
        (dashboard) lib/phoenix/endpoint/render_errors.ex:34: Dashboard.Endpoint.call/2
        (plug) lib/plug/adapters/cowboy/handler.ex:15: Plug.Adapters.Cowboy.Handler.upgrade/4
        (cowboy) src/cowboy_protocol.erl:442: :cowboy_protocol.execute/4

Any help appreciated!

Registering serializers

I'm writing an oauth strategy that needs an extra serializer. Eventually I want to release it as hex package. I rather avoid instructing the package users to configure oauth2 with the extra serializer if I can avoid it as it might conflict with other libraries. At the moment I just deserialize the response myself. With the latest oauth2 version, the users will get a warning about the missing serializer. The solutions I can think of are:

  • Allow flagging request to skip deserialization
  • Allow flagging requests to skip warning
  • Add serializer registry (maybe ets based?) where libraries that depend on oauth could programmatically add serializers

What are your thoughts?

Make Content-Type in token_post_header configurable

Hi, for getting an access-token from the SoundCloud API I had to change lib/oauth2/client.ex#L177 from

put_header(client, "Content-Type", "application/x-www-form-urlencoded")

to

put_header(client, "Content-Type", "application/json")

otherwise I'd just get a 406 with an empty body back.
Is there a way to configure this or build it into my own strategy?

Thanks

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.