Coder Social home page Coder Social logo

ueberauth / ueberauth_example Goto Github PK

View Code? Open in Web Editor NEW
218.0 12.0 74.0 1.07 MB

Example Phoenix application using Überauth for authentication

Home Page: http://ueberauth-example.herokuapp.com

License: MIT License

JavaScript 6.65% Elixir 68.57% HTML 7.48% SCSS 0.99% CSS 16.32%
ueberauth strategies phoenix example example-project

ueberauth_example'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_example's People

Contributors

aleciavogel avatar axelson avatar chulkilee avatar collegeimprovements avatar dependabot[bot] avatar doomspork avatar hajto avatar mariusbutuc avatar maxbeizer avatar mnebuerquo avatar ramortegui avatar rerb avatar rishibaldawa avatar shhavel avatar sobolevn avatar tessellator avatar timwis avatar vbrazo avatar woolfred avatar wribln avatar yordis avatar yuyabee avatar zacck 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

ueberauth_example's Issues

DB Schema?

I don't see any migration files in priv/repo/migrations. Wouldn't this mean that downloading this repo and trying to run it locally wouldn't work because the database can not be created with the proper columns?

Failed to authenticate

Hello

I tried running the example with Facebook but I still get failed to authenticate.
Why is that?
[debug] Processing by UeberauthExample.AuthController.request/2 Parameters: %{"provider" => "facebook"} Pipelines: [:browser] [info] Sent 302 in 1ms [debug] UeberauthExample.AuthController halted in Ueberauth.call/2 [info] GET /auth/facebook/callback [debug] Processing by UeberauthExample.AuthController.callback/2 Parameters: %{"code" => "AQB0kWhD619CpLsWrgSWunwxFqK0ZyJuBGKe-8AqErrGJsKbjvgGQg7-ezGsMu22A8DPSCB-Ykir-NJ3PEsgpDAjX3ZyFL9iIHgicc61Pghf6be3mn41derQwfUdLfTkD73qWjKxHm84DA-2QV3V5AjHyHZf1JpGpCbmgdq0EnldcZqIKjOBe3YNl5UUSDa92dbiC4JBSKmnaGxRDy8S1NHZINFoF5UO_iqdObfecAoadSKAI4p5IExrjN9-P8LnZkEvm82ECgGd9AWfHkAYaUYjsnsFirYfKLJjg7k9O6FQN4FfU160nUC6XN7P4KjnJr45abdtHdpFQSonyztrBwSw", "provider" => "facebook"} Pipelines: [:browser]

`AuthController` test example

Hey!

First of all, thank you very much for your hard work! Your contribution is great!

This repository has great value filling in the big picture when looking for more information beyond the documentation! I'm pretty sure, many of us - developers would appreciate if you were able to add some examples of how to test the callback functions (how to set proper :assigns for both of :ueberauth_failure and :ueberauth_auth).

I'm not sure how to tackle that properly - I've tried with naive approach like:

  test "GET /auth/facebook/callback", %{conn: conn} do
    conn =
      conn
      |> assign(:ueberauth_failure, "failed!")

    conn = get conn, "/auth/facebook/callback"

    assert html_response(conn, 200) =~ "Oh noes"
  end

but unfortunately, the plug tries to do it's job effectively failing the tests.

As a proof, when IO.inspect-ing the the ueberauth_failure: failure:

%Ueberauth.Failure{errors: [%Ueberauth.Failure.Error{message: "No code received",
   message_key: "missing_code"}], provider: :facebook,
 strategy: Ueberauth.Strategy.Facebook}

Thank you for your help!

Strange error with brunch

I have never actually seen something like this.

[info] Running UeberauthExample.Endpoint with Cowboy using http://localhost:4000

Fatal error in ../deps/v8/src/api.cc, line 1062

Check failed: !value_obj->IsJSReceiver() || value_obj->IsTemplateInfo().

==== C stack trace ===============================

0   node                                0x00000001008c6d19 v8::base::debug::StackTrace::StackTrace() + 19
1   node                                0x00000001008c5a31 V8_Fatal + 233
2   node                                0x0000000100146038 v8::Template::SetAccessorProperty(v8::Local<v8::Name>, v8::Local<v8::FunctionTemplate>, v8::Local<v8::FunctionTemplate>, v8::PropertyAttribute, v8::AccessControl) + 0
3   fse.node                            0x00000001044e6bb1 fse::FSEvents::Initialize(v8::Local<v8::Object>) + 197
4   node                                0x00000001007c6ed3 node::DLOpen(v8::FunctionCallbackInfo<v8::Value> const&) + 860
5   node                                0x000000010016a408 v8::internal::FunctionCallbackArguments::Call(void (*)(v8::FunctionCallbackInfo<v8::Value> const&)) + 340
6   node                                0x00000001001b1bdf v8::internal::MaybeHandle<v8::internal::Object> v8::internal::(anonymous namespace)::HandleApiCallHelper<false>(v8::internal::Isolate*, v8::internal::Handle<v8::internal::HeapObject>, v8::internal::Handle<v8::internal::HeapObject>, v8::internal::Handle<v8::internal::FunctionTemplateInfo>, v8::internal::Handle<v8::internal::Object>, v8::internal::BuiltinArguments) + 915
7   node                                0x00000001001b11b9 v8::internal::Builtin_Impl_HandleApiCall(v8::internal::BuiltinArguments, v8::internal::Isolate*) + 281
8   ???                                 0x00001622ca2843a7 0x0 + 24338676335527

Steps to reproduce

  1. clone master
  2. mix deps.get && npm install
  3. export SECRET_KEY_BASE=$(mix phoenix.gen.secret)
  4. mix phoenix.server

My setup

Elixir

» elixir --version
Erlang/OTP 19 [erts-8.2.2] [source] [64-bit] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false] [dtrace]

Elixir 1.4.2

node

» node --version
v7.9.0

npm

» npm --version
4.2.0

os

» uname -a
Darwin Mackbook-Nikita 15.6.0 Darwin Kernel Version 15.6.0: Fri Feb 17 10:21:18 PST 2017; root:xnu-3248.60.11.4.1~1/RELEASE_X86_64 x86_64

Facebook login not working

The facebook login when accessing through the heroku app says the app is still in dev phase and so doesn't work.

Error with Elixir 1.8

Running this with Elixir 1.8 I get the following error:

== Compilation error in file lib/ueberauth_example_web/views/auth_view.ex ==
** (BadMapError) expected a map, got: {:safe, ""}
    (eex) lib/eex/engine.ex:161: EEx.Engine.handle_begin/1
    (eex) lib/eex/compiler.ex:54: EEx.Compiler.generate_buffer/4
    (phoenix) lib/phoenix/template.ex:378: Phoenix.Template.compile/2
    (phoenix) lib/phoenix/template.ex:186: anonymous fn/3 in Phoenix.Template."MACRO-__before_compile__"/2
    (elixir) lib/enum.ex:1940: Enum."-reduce/3-lists^foldl/2-0-"/3
    (phoenix) expanding macro: Phoenix.Template.__before_compile__/1
    lib/ueberauth_example_web/views/auth_view.ex:1: UeberauthExampleWeb.AuthView (module)
    (elixir) lib/kernel/parallel_compiler.ex:208: anonymous fn/4 in Kernel.ParallelCompiler.spawn_workers/6

Google auth fails due missing redirect_uri

As per instructions cloned from git, set the two environment variables, and run the server. Google's service throws an error about missing parameter. My client id, and secret are correct.

Authorization Error
Error 400: invalid_request
Missing required parameter: redirect_uri

DELETE logout redirection

When logging out, the example code uses a DELETE request, finished by a redirect:

  def delete(conn, _params) do
    conn
    |> put_flash(:info, "You have been logged out!")
    |> configure_session(drop: true)
    |> redirect(to: "/")
  end

In my situation, this causes an error (it seems like phx is trying to redirect to 'DELETE /', which of course is not defined.)

application=plug ][info] DELETE /
[application=plug ][debug] ** (Phoenix.Router.NoRouteError) no route found for DELETE / (Redacted.Web.Router)
    (redacted) lib/redacted/web/router.ex:1: Redacted.Web.Router.__match_route__/4
    (redacted) lib/phoenix/router.ex:302: Redacted.Web.Router.call/2
    (redacted) lib/redacted/web/endpoint.ex:1: Redacted.Web.Endpoint.plug_builder_call/2
    (redacted) lib/plug/debugger.ex:123: Redacted.Web.Endpoint."call (overridable 3)"/2
    (redacted) lib/redacted/web/endpoint.ex:1: Redacted.Web.Endpoint.call/2
    (plug) lib/plug/adapters/cowboy/handler.ex:15: Plug.Adapters.Cowboy.Handler.upgrade/4  

Is it expected ? I have a route set up for GET / (but it assumes the user is authenticated. Could that be the problem ?)

Github Actions Failing

Github actions fails as per issues with DB credentials, and It was fixed as part of #54 PR.

19:38:19.906 [error] GenServer #PID<0.3995.0> terminating
** (Postgrex.Error) FATAL 28000 (invalid_authorization_specification): role "runner" does not exist
    (db_connection) lib/db_connection/connection.ex:163: DBConnection.Connection.connect/2
    (connection) lib/connection.ex:622: Connection.enter_connect/5
    (stdlib) proc_lib.erl:249: :proc_lib.init_p_do_apply/3
Last message: nil
** (Mix) The database for UeberauthExample.Repo couldn't be created: FATAL 28000 (invalid_authorization_specification): role "runner" does not exist
##[error]Process completed with exit code 1.

login with username/password got cookie store expects conn.secret_key_base to be set

It happens with sign in with username/password
Can anyone help to solve this?

osboxes@osboxes:~/projects/ueberauth_example$ sudo mix phoenix.server 
Compiling 13 files (.ex)
Generated ueberauth_example app
[info] Running UeberauthExample.Endpoint with Cowboy using http://localhost:4000
29 Oct 05:44:40 - info: compiled 5 files into 2 files, copied 3 in 4257ms
[info] GET /
[debug] Processing by UeberauthExample.PageController.index/2
  Parameters: %{}
  Pipelines: [:browser]
[info] Sent 200 in 79ms
[error] backend port not found: :inotifywait

[info] GET /auth/identity
[debug] Processing by UeberauthExample.AuthController.request/2
  Parameters: %{"provider" => "identity"}
  Pipelines: [:browser]
[info] Sent 500 in 160ms
[error] #PID<0.515.0> running UeberauthExample.Endpoint terminated
Server: localhost:4000 (http)
Request: GET /auth/identity
** (exit) an exception was raised:
    ** (ArgumentError) cookie store expects conn.secret_key_base to be set
        (plug) lib/plug/session/cookie.ex:157: Plug.Session.COOKIE.validate_secret_key_base/1
        (plug) lib/plug/session/cookie.ex:152: Plug.Session.COOKIE.derive/3
        (plug) lib/plug/session/cookie.ex:103: Plug.Session.COOKIE.put/4
        (plug) lib/plug/session.ex:92: anonymous fn/3 in Plug.Session.before_send/2
        (elixir) lib/enum.ex:1623: Enum."-reduce/3-lists^foldl/2-0-"/3
        (plug) lib/plug/conn.ex:961: Plug.Conn.run_before_send/2
        (plug) lib/plug/conn.ex:392: Plug.Conn.send_resp/1
        (ueberauth_example) web/controllers/auth_controller.ex:1: UeberauthExample.AuthController.action/2
        (ueberauth_example) web/controllers/auth_controller.ex:1: UeberauthExample.AuthController.phoenix_controller_pipeline/2
        (ueberauth_example) lib/ueberauth_example/endpoint.ex:1: UeberauthExample.Endpoint.instrument/4
        (ueberauth_example) lib/phoenix/router.ex:261: UeberauthExample.Router.dispatch/2
        (ueberauth_example) web/router.ex:1: UeberauthExample.Router.do_call/2
        (ueberauth_example) lib/ueberauth_example/endpoint.ex:1: UeberauthExample.Endpoint.phoenix_pipeline/1
        (ueberauth_example) lib/plug/debugger.ex:123: UeberauthExample.Endpoint."call (overridable 3)"/2
        (ueberauth_example) lib/ueberauth_example/endpoint.ex:1: UeberauthExample.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

Github not working with other apps?

Hi, I am failry new to Elixir and Phoenix and am just following guides etc and I got a Github auth to actually work in my local. I then checked and tested https://ueberauth-example.herokuapp.com/ and every other link works except Github, which gives me a failed to authenticate error (see screenshot)
screen shot 2016-08-24 at 9 05 30 am

I noticed though that it works again if I use an incognito window. Not sure if this is a legit issue but does that mean I can only have one app running that uses uberauth / github? Or am I doing something wrong here?

As additional info, I have a sample app that closely follows https://github.com/ueberauth/ueberauth_github. I've set it up in Github to point to localhost and it actually works:

screen shot 2016-08-24 at 9 08 37 am

Problems with username/password login..

I get this error when I try to access the login with username/password page:

ArgumentError at GET /auth/identity
cookie store expects conn.secret_key_base to be set

Logout does not work

Hello i´m just testing the identity.I deleted all but except identity.

However the logout is not working...
IT does nothing and the cookie is still set

can you help?

Travis CI Failing

Hello,

Master branch: Travis-CI is broken.

PR #55 will fix it, it also removes dogma and add mix format and mix credo --strict

Missing step in README.md

When attempting to run the sample code, there needs to be a 'mix ecto.create' step before attempting to start the phx.server. I don't understand why as the sample code does not seem to make use of a database. I am not sure if this is a missing piece of documentation or a piece of code needing adjustment.

Error - no function clause matching in Poison.Encoder.Any.encode/2

Getting following error for trying Login with Slack and Uberauth? Any known issue?

[error] #PID<0.456.0> running UeberauthExample.Endpoint terminated
Server: localhost:4000 (http)
Request: GET /auth/slack/callback?code=13091934864.128919569987.2438c05d6d&state=
** (exit) an exception was raised:
    ** (FunctionClauseError) no function clause matching in Poison.Encoder.Any.encode/2
        (ueberauth_example) lib/poison_encoder.ex:2: Poison.Encoder.Any.encode({:token, "xoxp-13091934864-116065375156-129072094709-d990cdc1e1677e9935b310a7c2d49f07"}, [])
        (poison) lib/poison/encoder.ex:232: anonymous fn/3 in Poison.Encoder.List.encode/3
        (poison) lib/poison/encoder.ex:233: Poison.Encoder.List.encode/3
        (poison) lib/poison.ex:41: Poison.encode!/2
        (oauth2) lib/oauth2/request.ex:13: OAuth2.Request.request/5
        (oauth2) lib/oauth2/access_token.ex:221: OAuth2.AccessToken.request/6
        (ueberauth_slack) lib/ueberauth/strategy/slack.ex:167: Ueberauth.Strategy.Slack.fetch_auth/2
        (ueberauth_slack) lib/ueberauth/strategy/slack.ex:65: Ueberauth.Strategy.Slack.handle_callback!/1
        (ueberauth) lib/ueberauth/strategy.ex:299: Ueberauth.Strategy.run_callback/2
        (ueberauth_example) web/controllers/auth_controller.ex:1: UeberauthExample.AuthController.phoenix_controller_pipeline/2
        (ueberauth_example) lib/ueberauth_example/endpoint.ex:1: UeberauthExample.Endpoint.instrument/4
        (ueberauth_example) lib/phoenix/router.ex:261: UeberauthExample.Router.dispatch/2
        (ueberauth_example) web/router.ex:1: UeberauthExample.Router.do_call/2

Update the project to Phoenix 1.13

Can we please update the project to the latest Phoenix (and other dependency) versions?
For someone who is completely new to Phoenix, the older versions can be confusing.

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.