Code Monkey home page Code Monkey logo

ueberauth_facebook's Introduction

Überauth

Build Status Codecov Inline docs Hex Version Hex docs Total Download License Last Updated

An Elixir Authentication System for Plug-based Web Applications

Ueberauth is a two-phase authentication framework that provides a clear API - allowing for many strategies to be created and shared within the community. It is heavily inspired by Omniauth. You could call it a port but it is significantly different in operation - but almost the same concept. Huge hat tip to Intridea.

Ueberauth provides only the initial authentication challenge, (initial OAuth flow, collecting the information from a login form, etc). It does not authenticate each request, that's up to your application. You could issue a token or put the result into a session for your applications needs. Libraries like Guardian can help you with that aspect of authentication.

The two phases are request and callback. These phases are implemented by Strategies.

Strategies

Strategies are plugs that decorate or intercept requests (or both).

Strategies implement the two phases and then may allow the request to flow through to your downstream plugs. Implementing the request and callback phases is optional depending on the strategies requirements. If a strategy does not redirect, the request will be decorated with Ueberauth information and allowed to carry on through the pipeline.

See the full list of the strategies on the Wiki.

Request Phase

The request phase is where you request information about the user. This could be a redirect to an OAuth2 authorization url or a form for collecting username and password. The request phase is concerned with only the collection of information. When a request comes in on the request phase url the relevant strategy will receive the handle_request! call.

In some cases (default) the application using Ueberauth is responsible for implementing the request phase. That is, you should set up a route to receive the request phase and provide a form etc. In some cases, like OAuth, the request phase is used to redirect your user to a 3rd party site to fulfill the request.

For example, an OAuth strategy for GitHub will receive the request phase url and stop the request, redirecting you to GitHub’s OAuth challenge url with some query parameters. Once you complete the GitHub OAuth flow, the user will be redirected back to the host site to the callback URL.

Another example is simple email/password authentication. A request is made by the client to the request phase path and the host application displays a form. The strategy will likely not do anything with the incoming handle_request! request and simply pass through to the application. Once the form is completed, the POST should go to the callback url where it is handled (passwords checked, users created / authenticated).

Callback Phase

The callback phase is where the fun happens. Once a successful request phase has been completed, the request phase provider (OAuth provider or host site, etc) should call the callback URL. The strategy will intercept the request via the handle_callback!. If successful, it should prepare the connection so the Ueberauth.Auth struct can be created, or set errors to indicate a failure.

See Ueberauth.Strategy for more information on constructing the Ueberauth.Auth struct.

Looking for an example? Take a look ueberauth/ueberauth_example.

Setup

Add the dependency

# mix.exs

defp deps do
  # Add the dependency
  [{:ueberauth, "~> 0.10"}]
end

Fetch the dependencies

mix deps.get

Configuring providers

In your configuration file (config/config.exs) provide a list of the providers you intend to use. For example:

config :ueberauth, Ueberauth,
  providers: [
    facebook: { Ueberauth.Strategy.Facebook, [ opt1: "value", opts2: "value" ] },
    github: { Ueberauth.Strategy.Github, [ opt1: "value", opts2: "value" ] }
  ]

This will define two providers for you. The general structure of the providers value is:

config :ueberauth, Ueberauth,
  providers: [
    <provider name>: { <Strategy Module>, [ <strategy options> ] }
  ]

We use the configuration options for defining these to allow for dependency injection in different environments. The provider name will be used to construct request and response paths (by default) but will also be returned in the Ueberauth.Auth struct as the provider field.

Once you've setup your providers, in your router you need to configure the plug to run. The plug should run before your application routes.

In phoenix, plug this module in your controller:

defmodule MyApp.AuthController do
  use MyApp.Web, :controller
  plug Ueberauth
  ...
end

Its URL matching is done via pattern matching rather than explicit runtime checks so your strategies will only fire for relevant requests.

Now that you have this, your strategies will intercept relevant requests for each strategy for both request and callback phases. The default urls are (for our Facebook & GitHub example)

# Request phase paths
/auth/facebook
/auth/github

# Callback phase paths
/auth/facebook/callback
/auth/github/callback

Customizing Paths

These paths can be configured on a per strategy basis by setting options on the provider.

Note: These paths are absolute

config :ueberauth, Ueberauth,
  base_path: "/login", # default is "/auth"
  providers: [
    identity: {Ueberauth.Strategies.Identity, [request_path: "/login/identity",
                                               callback_path: "/login/identity/callback"]}
  ]

Customizing JSON Serializer

Your JSON serializer can be configured depending on what you have installed in your application. Defaults to Jason.

config :ueberauth, Ueberauth,
  json_library: Poison # default is Jason

HTTP Methods

By default, all callback URLs are only available via the "GET" method. You can override this via options to your strategy.

providers: [
  identity: {Ueberauth.Strategies.Identity, [callback_methods: ["POST"]]}
]

Strategy Options

All options that are passed into your strategy are available at runtime to modify the behaviour of the strategy.

Copyright and License

Copyright (c) 2015 Sonny Scroggin

Released under the MIT License, which can be found in the repository in LICENSE.

ueberauth_facebook's People

Contributors

arghmeleg avatar doomspork avatar hanspagh avatar hykw avatar jabberfest avatar jbrowning avatar kianmeng avatar matthewlehner avatar msaurabhee avatar mtarnovan avatar nbw avatar nscyclone avatar scrogson avatar sibsibsib avatar smeevil avatar sobolevn avatar taj avatar tonnenpinguin avatar tt avatar ybur-yug 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

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

ueberauth_facebook's Issues

Cannot authenticate with client-initiated flow, fb signed request cookie is not read by ueberauth

Hello,

While navigating to /auth/facebook works fine, I cannot make a client side flow work properly.
The reason for preferring a client side flow is to authorize FB in a popup so that the user never leaves our site.

I have initialized the FB JS app with the app id and cookie set to true.

    FB.init({
        appId      : appId,
        cookie     : true,
        xfbml      : true,
        version    : 'v2.12'
    });

However in my case the failure callback is getting called on my auth controller because ueberath cannot find the code.

    def callback(%{assigns: %{ueberauth_failure: _fails}} = conn, _params) do
      conn
      |> put_flash(:error, "Failed to authenticate.")
      |> redirect(to: "/")
    end

Line of code in current project

The issue is that ueberauth_facebook does not read the code from the fb signed request cookie in case it cannot find it in the params.

Omniauth extracts the authorization code from the cookie like this:

omniauth code that extracts code either from params or cookie

omniauth cookie parsing logic

The cookie value is Base64 encoded and signed with HMAC-SHA256.

Could this be done here as well to support the client-initiated flow?

Omniauth client side flow documentation

Thanks in advance,

Mark

User Profile PIcture Always Returns Default Silhouette

It looks like Facebook made some changes that now require an access token to retrieve a user profile pic:

https://stackoverflow.com/questions/64434913/get-facebook-user-profile-image-after-facebook-changesoctober-24

This sounds like an easy PR. However, I am new to Elixir. And also, this makes me think that it may not be as easy to store user profile pictures in the database and use them on the client because an access token will eventually expire.

Any thoughts?

Is there a 0.2 version?

(Elixir / Phoenix newb, sorry for that)

I was working on getting it installed, and I got hung up on the deps section. I eventually got v 0.1.4 installed, but the README says 0.2 Is that just a copy/paste error from the ueberauth main repo?

Strategy crashes when OAuth code has been used or has expired

This strategy's callback handling uses OAuth2.Client.get_token!/1 and does not gracefully handle OAuth2.Error errors when fetching the access token. There are some common scenarios where this is raised such as when the OAuth code has already been used or has expired.

PR incoming.

Receive error: The code has been used or has expired

This had been working flawlessly for about 6 months, but after logging out, I keep getting the following error when trying to log back in:

%Ueberauth.Failure{
  errors: [
    %Ueberauth.Failure.Error{
      message: "The code has been used or has expired",
      message_key: "invalid_code"
    }
  ],
  provider: :facebook,
  strategy: Ueberauth.Strategy.Facebook
}

I've deleted the test FB app and created a new one, upgraded to the latest version of this package and also Ueberauth. Makes me think something has changed on FB's end.

Is there a way to debug this more? Would be happy to submit a PR

requires oauth 0.8.0

Other ueberauth modules require 0.8. In the mean time oauth2 0.9.0 was released which fixed a bunch of compile warnings.

Accepting state in query params

To connecting multiple accounts to a single user, need to maintain state between /auth/facebook and /auth/facebook/callback. for that we need to add state param in callback URL OAuth2 its supports that
and i also create a PR to fix this issue.

Release with latest changes from master

Please create a new release with the latest commit from master which locks the oauth2 lib to 0.6.0 because ueberauth_facebook 0.4.0 required oauth2 >0.5 which installs 0.7.0 and breaks everything.

Thanks

API calls from the server require an appsecret_proof argument

Error while using login. Seems need an extra token enforced by facebook graph apis

https://developers.facebook.com/docs/graph-api/securing-requests

[info] GET /auth/facebook/callback
[debug] Processing by SChat.AuthController.callback/2
  Parameters: %{"code" => "AQAxctwz8m9MPeMOYXzugx63Lcz_ow4VRrPztG3LpunvE5L0GRVfc-1BKJhyRPs3rSrsdFwegBRQSwJ4YiLLSvtyqW2mJLgZTtTGZticWfASqUVGXd6LFLdxAzuFuUiRXxgAZQiqZAaTW3Wcp6zPkBfPjKKCx9wzwsPKMiQbhLF1pshc6AqCGBvl-4kYHssWXGNjnIzwftfxnNGdvjJTRDWJ9gGtbpZpBWcJZ-HQwxzocHKrO-TahGapvJD54I4sJRhHdgt13mbLPT9a5sOu4ZPXk0ImFxccBfC_0mcdAK3NYQbKOoUImBDPsb_ebH4nzxV_siA4KfNLZw4qMauj-Q3R", "provider" => "facebook"}
  Pipelines: [:browser]
[info] Sent 500 in 1261ms
[error] #PID<0.621.0> running SChat.Endpoint terminated
Server: localhost:4000 (http)
Request: GET /auth/facebook/callback?code=AQAxctwz8m9MPeMOYXzugx63Lcz_ow4VRrPztG3LpunvE5L0GRVfc-1BKJhyRPs3rSrsdFwegBRQSwJ4YiLLSvtyqW2mJLgZTtTGZticWfASqUVGXd6LFLdxAzuFuUiRXxgAZQiqZAaTW3Wcp6zPkBfPjKKCx9wzwsPKMiQbhLF1pshc6AqCGBvl-4kYHssWXGNjnIzwftfxnNGdvjJTRDWJ9gGtbpZpBWcJZ-HQwxzocHKrO-TahGapvJD54I4sJRhHdgt13mbLPT9a5sOu4ZPXk0ImFxccBfC_0mcdAK3NYQbKOoUImBDPsb_ebH4nzxV_siA4KfNLZw4qMauj-Q3R
** (exit) an exception was raised:
    ** (CaseClauseError) no case clause matching: {:ok, %OAuth2.Response{body: %{"error" => %{"code" => 100, "fbtrace_id" => "DiYFdQdXoU/", "message" => "API calls from the server require an appsecret_proof argument", "type" => "GraphMethodException"}}, headers: [{"WWW-Authenticate", "OAuth \"Facebook Platform\" \"invalid_request\" \"API calls from the server require an appsecret_proof argument\""}, {"Access-Control-Allow-Origin", "*"}, {"Content-Type", "application/json"}, {"X-FB-Trace-ID", "DiYFdQdXoU/"}, {"X-FB-Rev", "2243920"}, {"Pragma", "no-cache"}, {"Cache-Control", "no-store"}, {"Expires", "Sat, 01 Jan 2000 00:00:00 GMT"}, {"X-FB-Debug", "XYGHwSYR8WhMN3De2MD74KDnfSTNXBrw4PxIm3zSJa/r/C0dAYqaj2Vv1sh3EDPHGsztlISlaxAg8eMqK5fPlQ=="}, {"Date", "Wed, 23 Mar 2016 11:52:20 GMT"}, {"Connection", "keep-alive"}, {"Content-Length", "154"}], status_code: 400}}
        (ueberauth_facebook) lib/ueberauth/strategy/facebook.ex:137: Ueberauth.Strategy.Facebook.fetch_user/2
        (ueberauth) lib/ueberauth/strategy.ex:299: Ueberauth.Strategy.run_callback/2
        (s_chat) web/controllers/auth_controller.ex:1: SChat.AuthController.phoenix_controller_pipeline/2
        (s_chat) lib/phoenix/router.ex:261: SChat.Router.dispatch/2
        (s_chat) web/router.ex:1: SChat.Router.do_call/2
        (s_chat) lib/s_chat/endpoint.ex:1: SChat.Endpoint.phoenix_pipeline/1
        (s_chat) lib/plug/debugger.ex:93: SChat.Endpoint."call (overridable 3)"/2
        (s_chat) lib/phoenix/endpoint/render_errors.ex:34: SChat.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

Question about auth via API server

Hi.
I have frontend server, where is plain javascript with Vue.js router, and backend, backed on Elixir. Is there possibility still use backend social single sign-on API server? Because all frontend views are separated from backend and I have problem rendering/redirecting users to login for facebook.

oauth2 0.7.0 OAuth2.Client.get_token!/1 API change causes issue on recent installations

Steps to reproduce:

  1. Create a new Phoenix application
  2. Follow the ueberauth_facebook README to add it to the app
  3. Add login code
  4. Try to log in

Trying to log in causes the following issue:

key :access_token not found in: %OAuth2.Client{authorize_url: "https://www.facebook.com/dialog/oauth", client_id: "...", client_secret: "...", headers: [], params: %{}, redirect_uri: "http://localhost:3000/auth/facebook/callback", site: "https://graph.facebook.com", strategy: Ueberauth.Strategy.Facebook.OAuth, token: %OAuth2.AccessToken{access_token: nil, expires_at: nil, other_params: %{"error" => %{"code" => 1, "fbtrace_id" => "...", "message" => "Error validating client secret.", "type" => "OAuthException"}}, refresh_token: nil, token_type: "Bearer"}, token_method: :post, token_url: "/oauth/access_token"}

I found that the issue was caused by the change of return value in OAuth2.Client.get_token!/1 in 'oauth2'. Specifically, ueberauth_facebook requires 'oauth2' using the '~> 0.5' version string. This causes new Phoenix apps to pull 'oauth2' 0.7.0 which causes the issue above.

Facebook login problem

I keep getting The parameter app_id is required response.

https://www.facebook.com/dialog/oauth?auth_type=&client_id=&redirect_uri=http%3A%2F%2Flocalhost%3A3000%2Fauth%2Ffacebook%2Fcallback&response_type=code&scope=email&state=

OTP 24 :crypto fix not in any release/not on Hex.pm

The crypto.hmac/3 -> crypto.mac/4 fix for OTP 24 is on master in this repo, but this fix has not been released to Hex.pm, which still serves Ueberauth FB 8.1.

Any timeline for hex publication, or ya'll need a hand with any related chores?

Thanks for the great FB Ueberauth package!

:crypto:hmac/3 has been removed in OTP24

==> ueberauth_facebook
Compiling 3 files (.ex)
warning: :crypto.hmac/3 is undefined or private, use crypto:mac/4 instead
  lib/ueberauth/strategy/facebook.ex:175: Ueberauth.Strategy.Facebook.hmac/3
:crypto.hmac(type, key, data)

Should be replaced by :crypto:mac/4, available from OTP 22.1 (compatible from Elixir 1.10+, required from Elixir 1.12+).

:crypto.mac(:hmac, type, key, data)

:erlang.system_info(:otp_release) can be used to get the OTP version and call the correct function.

fetch_user/2, inject locale param

Facebook has your name not only written in English(alphabet), but in language-specific name such as Umlaut, Japanese kanji, etc(I attache the snapshots, just in case).

You can get the language-specific name with https://graph.facebook.com/me?locale=ja_JP&access_token=xxxxxx. Is it possible to specify locale when you fetch user data?(maybe injecting it in fetch_user/2, path parameter)

facebook1

facebook2

Cannot authenticate with FB

I am getting this

[info] TLS :client: In state :wait_cert_cr at ssl_handshake.erl:1899 generated CLIENT ALERT: Fatal - Unknown CA

%Ueberauth.Failure{
  errors: [
    %Ueberauth.Failure.Error{
      message: "The code has been used or has expired",
      message_key: "invalid_code"
    }
  ],
  provider: :facebook,
  strategy: Ueberauth.Strategy.Facebook
}

any idea?

Currently published ueberauth_facebook incompatible with latest Ueberauth

#65 was merged but not released to Hex.pm, so I'm currently manually getting the master branch like so in mix.exs:

      {:ueberauth_facebook, git: "https://github.com/ueberauth/ueberauth_facebook.git", branch: "master"},

Any timeline for publication to Hex.pm, or is there anything I can do to help speed up the process?

Thank you for the great free software!

:connect_timeout

OAuth2.Error at GET /auth/facebook/callback
:connect_timeout
I tested on different machine and browsers its still happening

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.