Giter Club home page Giter Club logo

guardian_db'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.

guardian_db's People

Contributors

aledsz avatar alexfilatov avatar bcat-eu avatar cdesch avatar doomspork avatar dre1080 avatar ericsullivan avatar forest avatar fpalluel avatar hanspagh avatar hassox avatar hauntedhost avatar immortalin avatar lboekhorst avatar manukall avatar mgwidmann avatar michaelmano avatar parkerl avatar rhnonose avatar richdom2185 avatar rraub avatar samhamilton avatar talklittle avatar tanweerdev avatar techgaun avatar thiamsantos avatar timbuchwaldt avatar tteerawat avatar victorlcampos 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

guardian_db's Issues

Alternative token schema

Is there a way to declare and use an alternative Token schema?

My usecase requires multiple JWT tokens for a user, which requires some changes in the schema (mainly the primary keys).

A suggestion would be for it to be configurable, example:

config :guardian_db, GuardianDb,
  repo: MyApp.Repo,
  token: MyApp.Token

Tokens are not revoked

My on_revoke callback just rests there and is never called when user is signed out (Guardian's sign_out is called). I ended up switching to before_sign_out callback to get the logouts working:

  def before_sign_out(conn, location, _options) do
    claims = __MODULE__.Plug.current_claims(conn, key: location)
    token = __MODULE__.Plug.current_token(conn, key: location)

    if claims && token do
      with {:ok, _} <- Guardian.DB.on_revoke(claims, token) do
        {:ok, conn}
      end
    end

    {:ok, conn}
  end

This might be a Guardian issue since they state that sign_out will "remove from session (if fetched) and revoke the token", but in any case the current setup as described in readme doesn't seem to work.

Also as mentioned in #87 on_refresh callback as described triggers warning, there is really no such function yet (it is in the repository but is not released).

claims column - Not in use

The claims column on guardian_tokens is not being populated with any data.

GuardianDb.repo.insert cast(%Token{}, prepared_claims, [], [:jti, :aud, :iss, :sub, :exp, :jwt])

Also, the permission "pem" claim is not stored in the database. I'm creating a UI for token creation and wanted to show the permissions (which I can get from the JWT), but I was wondering if the DB token was supposed to include the permissions. I could also add the pem field to the table if that's helpful.

(undefined_table): relation "virtual: token" does not exist

Hi, seems there is an error with ecto schema definition

schema "virtual: token" do

guardian_db ~> 1.1

# mix guardian.db.gen.migration

defmodule MyApp.Repo.Migrations.Guardian.DB do
  use Ecto.Migration

  def change do
    create table(:guardian_tokens, primary_key: false) do
      add(:jti, :string, primary_key: true)
      add(:aud, :string, primary_key: true)
      add(:typ, :string)
      add(:iss, :string)
      add(:sub, :string)
      add(:exp, :bigint)
      add(:jwt, :text)
      add(:claims, :map)
      timestamps()
    end
  end
end
iex(1)> MyApp.Repo.all(Guardian.DB.Token)
[debug] QUERY ERROR source="virtual: token" db=10.2ms
SELECT v0."jti", v0."typ", v0."aud", v0."iss", v0."sub", v0."exp", v0."jwt", v0."claims", v0."inserted_at", v0."updated_at" FROM "virtual: token" AS v0 []
** (Postgrex.Error) ERROR 42P01 (undefined_table): relation "virtual: token" does not exist
    (ecto) lib/ecto/adapters/sql.ex:431: Ecto.Adapters.SQL.execute_and_cache/7
    (ecto) lib/ecto/repo/queryable.ex:133: Ecto.Repo.Queryable.execute/5
    (ecto) lib/ecto/repo/queryable.ex:37: Ecto.Repo.Queryable.all/4

cut a new release?

👋

I was attempting to implement the adapter behaviour described in your docs, and was warned that such a behaviour and spec did not exist.

Looks like the last release was in 2020. Given that folks seem to be using the adapter spec, are there any plans to cut a release?

Error in compiling 0.7.0

Running the following errors when trying to compile guardian_db 0.7.0:

==> guardian_db
Compiling 2 files (.ex)
warning: variable "timestamps" does not exist and is being expanded to "timestamps()", please use parentheses to remove the ambiguity or change the variable name
  lib/guardian_db.ex:40

warning: variable "interval" does not exist and is being expanded to "interval()", please use parentheses to remove the ambiguity or change the variable name
  lib/guardian_db/expired_sweeper.ex:38

warning: variable "self" does not exist and is being expanded to "self()", please use parentheses to remove the ambiguity or change the variable name
  lib/guardian_db/expired_sweeper.ex:68

warning: variable "interval" does not exist and is being expanded to "interval()", please use parentheses to remove the ambiguity or change the variable name
  lib/guardian_db/expired_sweeper.ex:68

warning: variable "opts" is unused
  lib/guardian_db/expired_sweeper.ex:16


== Compilation error on file lib/guardian_db.ex ==
** (FunctionClauseError) no function clause matching in Keyword.get/3
    (elixir) lib/keyword.ex:150: Keyword.get(nil, :schema_name, nil)
    lib/guardian_db.ex:25: (module)
    lib/guardian_db.ex:18: (module)

My deps list:

defp deps do
    [{:phoenix, "~> 1.2.0"},
     {:phoenix_pubsub, "~> 1.0"},
     {:phoenix_ecto, "~> 3.0"},
     {:postgrex, ">= 0.0.0"},
     {:phoenix_html, "~> 2.6"},
     {:phoenix_live_reload, "~> 1.0", only: :dev},
     {:gettext, "~> 0.11"},
     {:cowboy, "~> 1.0"},
     {:bamboo, "~> 0.8"},
     {:comeonin, "~> 2.6"},
     {:corsica, "~> 0.5"},
     {:guardian, "~> 0.14"},
     {:guardian_db, "~> 0.7"},
     {:ja_serializer, "~> 0.11"},
     {:scrivener_ecto, "~> 1.1"}]
  end

Any help would be much appreciated! Thanks.

Compatibility with Guardian 1.0.0

Does anyone know if guardian 1.0.0-beta has any breaking changes that would require updating guardian_db to be compatible?

I was going to fork the project and see if I could get the current release to work with the latest guardian. I didn't know if there were any off the bat pitfalls.


Failed to use "guardian" (version 1.0.0-beta.0) because
  guardian_db (version 0.8.0) requires ~> 0.14
  mix.exs specifies ~> 1.0.0-beta

Missing guardian_db conf but the error is misleading

Hi

I missed guardian_db in config/config.exs and run mix compile, got below error:

== Compilation error on file lib/guardian_db.ex ==
** (FunctionClauseError) no function clause matching in Keyword.get/3
    (elixir) lib/keyword.ex:150: Keyword.get(nil, :schema_name, nil)
    lib/guardian_db.ex:25: (module)
    lib/guardian_db.ex:18: (module)

could not compile dependency :guardian_db, "mix compile" failed. You can recompile this dependency with "mix deps.compile guardian_db", update it with "mix deps.update guardian_db" or clean it with "mix deps.clean guardian_db"

According to Keyword:get/3, the first arg should be list type, however Application.get_env(:guardian_db, GuardianDb) default value is nil. Further more, I really hope some humanized message like "Application conf guardian_db missed" pop out.

BR
-Jack

GuardianDB 1.0.0 version does not exist in Hex

Readme.md instructions say that version you must to set into dependecies is:

{:guardian_db, "~> 1.0.0"}

But in Hex does no exist that version (https://hex.pm/packages/guardian_db) and there is an error if you try running mix deps.get

Running dependency resolution...

Failed to use "guardian_db" because
mix.exs specifies ~> 1.0.0

** (Mix) Hex dependency resolution failed, relax the version requirements of your dependencies or
unlock them (by using mix deps.update or mix deps.unlock). If you are unable to resolve the conflicts
you can try overriding with {:dependency, "~> 1.0", override: true}

guardian_db fails to compile with Ecto 3 rc (undefined function migrations_path/1)

See elixir-ecto/ecto#2763

== Compilation error in file lib/mix/tasks/guardian_db.gen.migration.ex ==
** (CompileError) lib/mix/tasks/guardian_db.gen.migration.ex:21: undefined function migrations_path/1
    (stdlib) lists.erl:1338: :lists.foreach/2
    (stdlib) erl_eval.erl:680: :erl_eval.do_apply/6

I'm in the midst of updating a Phoenix app to use Ecto 3 (and ecto_sql), but ran into this compile failure when updating guardian_db from 0.8 to 1.1.

https://github.com/ueberauth/guardian_db/blob/master/lib/mix/tasks/guardian_db.gen.migration.ex#L21

function Guardian.DB.on_refresh/2 is undefined or private

Steps to reproduce:
Add hex dependency of guardian_db plus configurations and when project will be compiled, you will get this error.
Please release a new version. This will be fixed as we already have this fixed in current codebase

schema_name config option ignored

In my config/config.exs:

config :guardian_db, GuardianDb,
  repo: CommunitiesOfHope.Repo,
  schema_name: "user_tokens",

And my migration:

defmodule CommunitiesOfHope.Repo.Migrations.GuardianDb do
  use Ecto.Migration

  def change do
    create table(:user_tokens, primary_key: false) do
      add :jti, :string, primary_key: true
      add :aud, :string, primary_key: true
      add :typ, :string
      add :iss, :string
      add :sub, :string
      add :exp, :bigint
      add :jwt, :text
      add :claims, :map
      timestamps()
    end
  end
end

But when I try to login, I get the following error:

ERROR 42P01 (undefined_table): relation "guardian_tokens" does not exist

It seems that the schema_name config option is being ignored.


Elixir Version: 1.4.5
Erlang Version: 20
Dependency Versions:

$ mix deps | grep \* | sort
* bamboo 0.8.0 (Hex package) (mix)
* base64url 0.0.1 (Hex package) (rebar)
* bunt 0.2.0 (Hex package) (mix)
* certifi 1.2.1 (Hex package) (rebar3)
* comeonin 3.0.2 (Hex package) (mix)
* connection 1.0.4 (Hex package) (mix)
* cowboy 1.1.2 (Hex package) (rebar3)
* cowlib 1.0.2 (Hex package) (rebar3)
* credo 0.8.1 (Hex package) (mix)
* csvlixir 1.0.0 (Hex package) (mix)
* db_connection 1.1.2 (Hex package) (mix)
* decimal 1.3.1 (Hex package) (mix)
* ecto 2.1.4 (Hex package) (mix)
* elixir_make 0.4.0 (Hex package) (mix)
* ex_admin 0.9.0-dev (https://github.com/smpallen99/ex_admin.git) (mix)
* ex_queb 1.0.0 (Hex package) (mix)
* exactor 2.2.3 (Hex package) (mix)
* fs 0.9.1 (Hex package) (rebar)
* gettext 0.13.1 (Hex package) (mix)
* guardian 0.14.4 (Hex package) (mix)
* guardian_db 0.8.0 (Hex package) (mix)
* hackney 1.8.6 (Hex package) (rebar3)
* idna 5.0.2 (Hex package) (rebar3)
* inflex 1.8.1 (Hex package) (mix)
* jose 1.8.4 (Hex package) (mix)
* metrics 1.0.1 (Hex package) (rebar3)
* mime 1.1.0 (Hex package) (mix)
* mimerl 1.0.2 (Hex package) (rebar3)
* phoenix 1.2.4 (Hex package) (mix)
* phoenix_ecto 3.2.3 (Hex package) (mix)
* phoenix_html 2.9.3 (Hex package) (mix)
* phoenix_live_reload 1.0.8 (Hex package) (mix)
* phoenix_pubsub 1.0.2 (Hex package) (mix)
* plug 1.3.5 (Hex package) (mix)
* poison 2.2.0 (Hex package) (mix)
* poolboy 1.5.1 (Hex package) (rebar)
* postgrex 0.13.3 (Hex package) (mix)
* ranch 1.3.2 (Hex package) (rebar3)
* scrivener 2.3.0 (Hex package) (mix)
* scrivener_ecto 1.2.2 (Hex package) (mix)
* ssl_verify_fun 1.1.1 (Hex package) (rebar)
* ueberauth 0.4.0 (Hex package) (mix)
* ueberauth_identity 0.2.3 (Hex package) (mix)
* unicode_util_compat 0.2.0 (Hex package) (rebar3)
* uuid 1.1.7 (Hex package) (mix)
* xain 0.6.0 (Hex package) (mix)

Sweeper not working

I still see the expired tokens in the database after they had expired, I expect them to be erased automatically after expiration. Any idea what to look for and check? Thank you.

Guardian DB 0.7.0 fails to compile using Elixir 1.4

It looks like a new release needs to be tagged because the fixes appear to be in master but, currently when trying to compile guardian_db as a dependency in a project I get compilation error.

  mix deps.compile
==> base64url (compile)
  Compiled src/base64url.erl
  warning: variable "erlc_options" does not exist and is being expanded to
  "erlc_options()", please use parentheses to remove the ambiguity or
  change the variable name
  /Users/st23am/src/elixir/test_guardian_db/deps/jose/mix.exs:8

  warning: variable "deps" does not exist and is being expanded to
  "deps()", please use parentheses to remove the ambiguity or change the
  variable name
  /Users/st23am/src/elixir/test_guardian_db/deps/jose/mix.exs:11

  warning: variable "description" does not exist and is being expanded
  to "description()", please use parentheses to remove the ambiguity
  or change the variable name
  /Users/st23am/src/elixir/test_guardian_db/deps/jose/mix.exs:19

  warning: variable "package" does not exist and is being expanded
  to "package()", please use parentheses to remove the ambiguity or
  change the variable name
  /Users/st23am/src/elixir/test_guardian_db/deps/jose/mix.exs:20

  ==> jose
  Compiling 87 files (.erl)
Compiling 8 files (.ex)
  warning: HashDict.size/1 is deprecated, use maps and the Map
  module instead
  lib/jose/poison/lexical_encoder.ex:199



  README.md
  Generated jose app
==> poolboy (compile)
  Compiled src/poolboy_worker.erl
  Compiled src/poolboy_sup.erl
  Compiled src/poolboy.erl
  ==> decimal
Compiling 1 file (.ex)
  Generated decimal app
  ==> poison
Compiling 4 files (.ex)
  warning: HashDict.size/1 is deprecated, use maps and the Map
  module instead
  lib/poison/encoder.ex:283

  Generated poison app
  ==> ecto
Compiling 68 files (.ex)
  warning: behaviour DBConnection is undefined
  lib/ecto/adapters/sql/sandbox.ex:284

  warning: behaviour DBConnection.Pool is undefined
  lib/ecto/adapters/sql/sandbox.ex:356

  Generated ecto app
  ==> uuid
Compiling 1 file (.ex)
  Generated uuid app
  ==> mime
Compiling 1 file (.ex)
  Generated mime app
  ==> plug
Compiling 44 files (.ex)
  Generated plug app
  ==> guardian
Compiling 21 files (.ex)

  == Compilation error on file lib/guardian.ex ==
  ** (RuntimeError) Guardian is not configured
lib/guardian.ex:26: (module)
  (stdlib) erl_eval.erl:670: :erl_eval.do_apply/6

  could not compile dependency :guardian, "mix
  compile" failed. You can recompile this
  dependency with "mix deps.compile guardian",
  update it with "mix deps.update guardian" or
  clean it with "mix deps.clean guardian"

Here is a repo you can use to reproduce the error: https://github.com/st23am/test_guardian_db_compile

hash of tokens

How is the tokens stored in the db, would make sense to store the sessions as hash only? or have option of storing them as hash. One user case is where using JWT as a api key for server to server communications and using the same auth framework(guardian + guardian db) for user sessions but a token that lives forever.

Dependency Update

Failed to use "ecto_sql" (version 3.1.1) because
  guardian_db (version 2.0.0) requires ~> 3.0.0

Ecto.StaleEntryError when using Guardian.DB.on_revoke

In looking up this issue I found #102 and saw that it had been fixed, closed, and merged. But then the code that solved this was refactored in 781d076, removed, and never actually released.

We get tons of Ecto.StaleEntryErrors when using Guardian.DB.on_revoke. Was this written out by mistake, or was there a reason for removing it? Do you have any advice on how to fix this?

Tokens not being tracked in database

I've installed guardian_db 1.1.0 with guardian 1.0.1 in my Phoenix application. I have followed the README by adding the configs, adding the lifecycle methods to my token module, and running the migration as instructed. However, when I try signing in an user with Guardian.encode_and_sign, the login is successful but I don't see a token entry added to the guardian_tokens table. Am I missing something?

My token module is just basically copying and pasting the snippet from the README:

defmodule ApiServer.Auth.Tokens do
  use Guardian, otp_app: :api_server

  def after_encode_and_sign(resource, claims, token, _options) do
    with {:ok, _} <- Guardian.DB.after_encode_and_sign(resource, claims["typ"], claims, token) do
      {:ok, token}
    end
  end

  def on_verify(claims, token, _options) do
    with {:ok, _} <- Guardian.DB.on_verify(claims, token) do
      {:ok, claims}
    end
  end

  def on_refresh({old_token, old_claims}, {new_token, new_claims}, _options) do
    with {:ok, _} <- Guardian.DB.on_refresh({old_token, old_claims}, {new_token, new_claims}) do
      {:ok, {old_token, old_claims}, {new_token, new_claims}}
    end
  end

  def on_revoke(claims, token, _options) do
    with {:ok, _} <- Guardian.DB.on_revoke(claims, token) do
      {:ok, claims}
    end
  end
end

Also, when I compile and run the server, I get the following warning:

function Guardian.DB.on_refresh/2 is undefined or private

Not sure what else I need to do to get it working. Any help will be greatly appreciated. Thanks!

no case clause matching error when calling api_sign_in

In my Phoenix app, I am using Guardian and GuardianDb for user authorization. Initially, I was only using Guardian and everything with the auth process was working just fine. However, after adding GuardianDb to the mix (for token storage), token records are being created correctly, but I'm getting a no case clause matching error that's throwing a wrench into the works and I cannot seem to figure out how to get around it (perhaps also worth noting here that I'm using Phoenix as an API with a React front-end). Here's how it's all going down...

First off, from mix.exs:

{:guardian, "~> 0.14"},
{:guardian_db, "~> 0.8.0"},

and, as specified in the docs, config.exs:

config :guardian, Guardian,
  hooks: GuardianDb,
  issuer: "MyApp",
  ttl: {30, :days},
  verify_issuer: true,
  serializer: MyApp.GuardianSerializer

config :guardian_db, GuardianDb,
  repo: MyApp.Repo,
  schema_name: "guardian_tokens"

and, to be comprehensive, from router.ex:

pipeline :api do
  plug CORSPlug, [origin: "http://localhost:3000"]
  plug :accepts, ["json"]
  plug Guardian.Plug.VerifyHeader, realm: "Bearer"
  plug Guardian.Plug.LoadResource
end

The error is raised during the create action in session_controller.ex:

def create(conn, %{"person" => person_params}) do
  case authenticate(person_params) do
    {:ok, person} ->
      new_conn = Guardian.Plug.api_sign_in(conn, person, :access)
      jwt = Guardian.Plug.current_token(new_conn)

      json new_conn, %{status: "ok", data: person, meta: %{token: jwt}}
    :error ->
      json(conn |> put_status(401), %{status: "error", message: "Invalid credentials"})
  end
end

When I try to call on this action, the desired record is created in the database - however, I get the following error (backslashes added for tidy formatting):

(CaseClauseError) no case clause matching:
{:ok, {%MyApp.Person{__meta__: #Ecto.Schema.Metadata<:loaded, "people">, \
deleted_at: nil, email: "[email protected]", first_name: "FirstName", \
id: "people:Jz3bIt54283NvZb", inserted_at: ~N[2017-05-01 18:02:17.750603], \
last_name: "LastName", password: nil, updated_at: ~N[2017-05-01 18:02:17.750612]}, \
:access, %{"aud" => "people:Jz3bIt54283NvZb", "exp" => 1496441175, \
"iat" => 1493849175, "iss" => "MyApp", \
"jti" => "248e62ed-a2a2-4a0a-9e08-eae0190516c6", "pem" => %{}, \
"sub" => "Person:people:Jz3bIt54283NvZb", "typ" => "access"}, \
"eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJQZXJzb246cGVvcGxlOkp6M2JJdEpnTzU4M052WmIiLCJleHAiOjE0OTY0NDExNzUsImlhdCI6MTQ5Mzg0OTE3NSwiaXNzIjoiUGhvZW5peEJhY2tlbmQiLCJqdGkiOiIyNDhlNjJkZC1hMmEyLTRhMGEtOWYwOC1lYWUwMTkwNTE2YzYiLCJwZW0iOnt9LCJzdWIiOiJQZXJzb246cGVvcGxlOkp6M2JJdEpnTzU4M052WmIiLCJ0eXAiOiJhY2Nlc3MifQ.DliX044wFmKpCrawuH3W_DoCya2VYAdrxZfwWEGWtW_ymDxXmQgV6XL3bHRkPKhSHziaFQFMvHIGS9yKtBfTkg"}}

With the trace:

lib/guardian.ex:100: Guardian.encode_from_hooked/1
lib/guardian/plug.ex:178: Guardian.Plug.api_sign_in/4
(phoenix_backend) web/controllers/session_controller.ex:9: MyApp.SessionController.create/2

The first two lines from that trace are from the dependencies, and the third line refers to Guardian.Plug.api_sign_in(conn, person, :access) from the controller above.

Now before I added GuardianDb, this controller action worked perfectly, but it seems now that the process is getting hung up in one of the hooks in the dependencies, and I'm not sure how to proceed.

For reference, the first line in the trace points to call_after_encode_and_sign_hook in the function encode_from_hooked:

defp encode_from_hooked({:ok, {resource, type, claims_from_hook}}) do
  {:ok, jwt} = encode_claims(claims_from_hook)
  case call_after_encode_and_sign_hook( # THIS IS LINE 100
    resource,
    type,
    claims_from_hook, jwt
  ) do
    :ok -> {:ok, jwt, claims_from_hook}
    {:error, reason} -> {:error, reason}
  end
end

and the second line in the trace points to encode_and_sign in the api_sign_in function:

def api_sign_in(conn, object, type, new_claims) do
  the_key = Map.get(new_claims, :key, :default)
  new_claims = Map.delete(new_claims, :key)

  case Guardian.encode_and_sign(object, type, new_claims) do # THIS IS LINE 178
    {:ok, jwt, full_claims} ->
      conn
      |> set_current_resource(object, the_key)
      |> set_claims({:ok, full_claims}, the_key)
      |> set_current_token(jwt, the_key)
      |> Guardian.hooks_module.after_sign_in(the_key)

    {:error, reason} ->
      set_claims(conn, {:error, reason}, the_key)
  end
end

Again, I just want to emphasize that the controller action worked perfectly before incorporating GuardianDb. Now that I've added GuardianDb, the record is created correctly in the database but it seems to get hung up in the process and new_conn is not correctly defined.

Perhaps I'm not using the library correctly or not making the right function call? Any clarification would be appreciated, but I thought it was worth writing about here since the trace pointed to the deps.

Refresh / Logout not working

I've been using past verions of Guardian \ Guardian DB and has been working fine. I've decided to update all packages, and I've update all sucessfully except this one.

I've check multiple times Guardian and Guardian Db documentation and can't find the solution for my problem.

I've 2 tests in my project, one to test refresh token and another to test logout.
For refresh token I use the following code:

case MyApp.Guardian.refresh(existing_jwt, ttl: {1, :week}) do
      {:ok, {_old_token, _old_claims}, {new_jwt, _new_claims}} ->

For logout I use the following code:

MyApp.Guardian.revoke(jwt)

I've checked the documentation, it says to use Guardian.revoke! but that doesn't exists anymore.

The thing I notice is, using token_types: ["refresh_token"], refresh works, but logout doesn't. If I remove token_types: ["refresh_token"] logout works, but refresh doesn't. In documentation it says that if token_types isn't present, should keep everything, right ?

The error that I get when trying to pass the refresh test is:

Guardian.DB.on_verify(claims, token)
{:error, :token_not_found}

If I add token_types: ["refresh_token"], refresh tokens is valid, but the revoke token doesn't revoke the token (keep it valid until expires).

Am I missing something here ?

How to add more columns to 'guardian_tokens' table?

Currently, the following migration is generated during setup:

create table(:guardian_tokens, primary_key: false) do
  add(:jti, :string, primary_key: true)
  add(:aud, :string, primary_key: true)
  add(:typ, :string)
  add(:iss, :string)
  add(:sub, :string)
  add(:exp, :bigint)
  add(:jwt, :text)
  add(:claims, :map)
end

I have a multi-tenant SaaS app, and each tenant gets their own schema in Postgres. So I need to add a new tenant column to this table so that I know which tenant each token belongs to.

Is this possible?

Compatibility with Guardian 2.0

It seems like Guardian goes 2.0. Does anyone know if guardian 2.0 has any breaking changes that would require updating guardian_db to be compatible?

Failed to use "guardian" (version 2.0.0) because
  guardian_db (version 2.0.1) requires ~> 1.0
  mix.exs specifies ~> 2.0

Warning when generating guardian db migration

Hello guys,
Not sure if here's the right place to post this kind of stuff but let me know if not.
I followed the steps described on README but after run mix guardian.db.gen.migration I got this error:

** (Mix) The task "guardian.db.gen.migration" could not be found because the module is named Mix.Tasks.Guardian.DB.Gen.Migration instead of Mix.Tasks.Guardian.Db.Gen.Migration as expected. Please rename it and try again

Could someone, please, give me a help?

The error message is pretty simple to understand what's going on but I'd like to know if there's something I can do on my end or it is already being fixed.

Throwing "no case clause matching" when use with GuardianDB

Hi, I upgraded the to the latest Guardian package, and ran in to this exception:

** (exit) an exception was raised:
    ** (CaseClauseError) no case clause matching: {:ok, {%ElixirTw.User{__meta__: #Ecto.Schema.Metadata<:loaded, "users">, crypted_password: nil, email: "[email protected]", id: 1, inserted_at: #Ecto.DateTime<2016-10-01 14:38:47>, name: "Mickey Chen", oauth_infos: #Ecto.Association.NotLoaded<association :oauth_infos is not loaded>, posts: #Ecto.Association.NotLoaded<association :posts is not loaded>, updated_at: #Ecto.DateTime<2016-10-01 14:38:47>}, nil, %{"aud" => "User:1", "exp" => 1485240250, "iat" => 1482648250, "iss" => "ElixirTW", "jti" => "ea6a199e-4e52-4472-96f9-e84ef0ad4dc1", "pem" => %{}, "sub" => "User:1", "typ" => "access"}, "eyJhbGciOiJFUzUxMiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJVc2VyOjEiLCJleHAiOjE0ODUyNDAyNTAsImlhdCI6MTQ4MjY0ODI1MCwiaXNzIjoiRWxpeGlyVFciLCJqdGkiOiJlYTZhMTk5ZS00ZTUyLTQ0NzItOTZmOS1lODRlZjBhZDRkYzEiLCJwZW0iOnt9LCJzdWIiOiJVc2VyOjEiLCJ0eXAiOiJhY2Nlc3MifQ.AZUR4vzOGuYFEW3z1vvms4VZjPGR6EC4XBjL0Hvmax3CSiU_uyLe7CIpUvXpybmo59MTZZN0ouOFvuaznPuQhDcAAMuUVRWgMjQmJRmJUzr0uEbvm3H-JBVZs0tp-FbtT8rLfC2ZuxAvob8G5v8GPpIObWlUO8LOiUaBD0aw2oWudyiq"}}
        (guardian) lib/guardian.ex:100: Guardian.encode_from_hooked/1
        (guardian) lib/guardian/plug.ex:117: Guardian.Plug.sign_in/4
        (elixir_tw) web/controllers/session_controller.ex:51: ElixirTw.SessionController.callback/2
        (elixir_tw) web/controllers/session_controller.ex:1: ElixirTw.SessionController.action/2
        (elixir_tw) web/controllers/session_controller.ex:1: ElixirTw.SessionController.phoenix_controller_pipeline/2
        (elixir_tw) lib/elixir_tw/endpoint.ex:1: ElixirTw.Endpoint.instrument/4
        (elixir_tw) lib/phoenix/router.ex:261: ElixirTw.Router.dispatch/2
        (elixir_tw) web/router.ex:1: ElixirTw.Router.do_call/2
        (elixir_tw) lib/elixir_tw/endpoint.ex:1: ElixirTw.Endpoint.phoenix_pipeline/1
        (elixir_tw) lib/plug/debugger.ex:123: ElixirTw.Endpoint."call (overridable 3)"/2
        (elixir_tw) lib/elixir_tw/endpoint.ex:1: ElixirTw.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

after some digging into the code I think it's a miss match between:

GuardianDb's [after_encode_and_sign] (https://github.com/hassox/guardian_db/blob/master/lib/guardian_db.ex#L77)

and

Guardian's https://github.com/ueberauth/guardian/blob/master/lib/guardian.ex#L105

If we just tweak the pattern a little bit to {:ok, _} it would resolve the issue.

GuardianDb.ExpiredSweeper is not available in release

Mix server works fine for me whether in dev or prod environments.

PORT=4000  MIX_ENV=prod mix phoenix.server
17:23:18.603 [info] Running App.Endpoint with Cowboy using http://localhost:4000
INITING THE SWEEPER 7200000

However, when I create a release and execute it, I get the following error. I'm likely missing a config variable - ie. this is likely not a bug.

Erlang/OTP 18 [erts-7.3] [source-d2a6d81] [64-bit] [smp:8:8] [async-threads:10] [hipe] [kernel-poll:false]

17:29:59.556 [info] Running App.Endpoint with Cowboy using http://localhost:4000
17:29:59.558 [info] Application app exited: Appstart(:normal, []) returned an error: shutdown: failed to start child: GuardianDb.ExpiredSweeper
    ** (EXIT) an exception was raised:
        ** (UndefinedFunctionError) function GuardianDb.ExpiredSweeper.start_link/0 is undefined (module GuardianDb.ExpiredSweeper is not available)
            GuardianDb.ExpiredSweeper.start_link()
            (stdlib) supervisor.erl:358: :supervisor.do_start_child/2
            (stdlib) supervisor.erl:341: :supervisor.start_children/3
            (stdlib) supervisor.erl:307: :supervisor.init_children/2
            (stdlib) gen_server.erl:328: :gen_server.init_it/6
            (stdlib) proc_lib.erl:240: :proc_lib.init_p_do_apply/3
{"Kernel pid terminated",application_controller,"{application_start_failure,app,{{shutdown,{failed_to_start_child,'Elixir.GuardianDb.ExpiredSweeper',{'EXIT',{undef,[{'Elixir.GuardianDb.ExpiredSweeper',start_link,[],[]},{supervisor,do_start_child,2,[{file,\"supervisor.erl\"},{line,358}]},{supervisor,start_children,3,[{file,\"supervisor.erl\"},{line,341}]},{supervisor,init_children,2,[{file,\"supervisor.erl\"},{line,307}]},{gen_server,init_it,6,[{file,\"gen_server.erl\"},{line,328}]},{proc_lib,init_p_do_apply,3,[{file,\"proc_lib.erl\"},{line,240}]}]}}}},{'Elixir.App',start,[normal,[]]}}}"}

Crash dump is being written to: erl_crash.dump...done
Kernel pid terminated (application_controller) ({application_start_failure,app,{{shutdown,{failed_to_start_child,'Elixir.GuardianDb.ExpiredSweeper',{'EXIT',{undef,[{'Elixir.GuardianDb.ExpiredSwee

I have attached my app.ex and config.exs below (App name obfuscated)

defmodule App do
  use Application

  # See http://elixir-lang.org/docs/stable/elixir/Application.html
  # for more information on OTP Applications
  def start(_type, _args) do
    import Supervisor.Spec

    # Define workers and child supervisors to be supervised
    children = [
      # Start the Ecto repository
      supervisor(App.Repo, []),
      # Start the endpoint when the application starts
      supervisor(App.Endpoint, []),
      # Start Presence when the application starts
      supervisor(App.Presence, []),
      # Start your own worker by calling: App.Worker.start_link(arg1, arg2, arg3)
      # worker(AppWorker, [arg1, arg2, arg3]),

      # https://github.com/hassox/guardian_db
      worker(GuardianDb.ExpiredSweeper, [])
    ]

    # See http://elixir-lang.org/docs/stable/elixir/Supervisor.html
    # for other strategies and supported options
    opts = [strategy: :one_for_one, name: App.Supervisor]
    Supervisor.start_link(children, opts)
  end

  # Tell Phoenix to update the endpoint configuration
  # whenever the application is updated.
  def config_change(changed, _new, removed) do
    App.Endpoint.config_change(changed, removed)
    :ok
  end
end
# Configure Guardian
# https://github.com/ueberauth/guardian
config :guardian, Guardian,
  allowed_algos: ["HS512"], # optional
  verify_module: Guardian.JWT,  # optional
  issuer: "App.#{Mix.env}",
  ttl: { 30, :days },
  verify_issuer: true, # optional
  secret_key: to_string(Mix.env),
  serializer: App.GuardianSerializer,
  hooks: GuardianDb,
  Permissions: %{
    default: [
      :read_profile,
      :write_profile,
      :read_token,
      :revoke_token
    ]
  }

# https://github.com/hassox/guardian_db
config :guardian_db, GuardianDb,
       repo: App.Repo,
       # schema_name: "tokens",
       sweep_interval: 120

Handle expired tokens at guardian_db itself

Hi,
How about adding some (1:100 for example) probability of running purge_expired_tokens! from create! function? Probably add config option autocleanup which is false by default (for those who want to implement or already have implemented some specific GC algorithms).
That's how a lot of software does GC jobs and would be helpful to have here as well I think.
Something like

def create!(claims, jwt) do
  if Dict.get(Application.get_env(:guardian_db, GuardianDb), :autoremove, false) and :random.uniform() >= 0.99 do
    purge_expired_tokens!
  end
  prepared_claims = claims |> Dict.put("jwt", jwt) |> Dict.put("claims", claims)
  GuardianDb.repo.insert cast(%Token{}, prepared_claims, [], [:jti, :typ, :aud, :iss, :sub, :exp, :jwt, :claims])
end

separated token schemes

Hey!
I want to have several different types of tokens in different schemes and manage them at the context level. But if I understand correctly, guardian provides api, where we can't pass another token model(some module that inherited from default Token model). Right?
It looks very not flexible

Missing dependency in README.md

I was trying to create a API with guardian and guardian_db for authentication, and I was getting this error:

** (Mix) Could not start application guardian_db: could not find application file: guardian_db.app

After some minutes I notice that the dependency "guardian_db" wasn't on my mix.exs file. I've checked the README.me both on guardian and guardian_db and both doesn't state that I need to add this dependency (but I think it should be obvious).

I've checked the package in https://hex.pm/packages/guardian_db and added to mix.exs.

Anyway should this be on the README.md of this project ?

Thanks

Do not fix ecto version

Hello.

I've tried to update dependencies of my project, but got this error:

* ecto (Hex package)
  the dependency ecto 3.4.5

  > In deps/guardian_db/mix.exs:
    {:ecto, "~> 3.0", [env: :prod, hex: "ecto", repo: "hexpm", optional: false]}

  does not match the requirement specified

  > In deps/ecto_sql/mix.exs:
    {:ecto, "~> 3.5.0", [env: :prod, hex: "ecto", repo: "hexpm", optional: false]}

Can you please replace ~> 3.0 with >= 3.0 for ecto and ecto_sql dependencies?
Current deps specification is too strict.

Problem with ecto mongodb

Env:

            {:phoenix, "~> 1.1.6"},
            {:phoenix_ecto, "~> 1.2.0"},
            {:mongodb_ecto, "~> 0.1.4"},
            {:guardian, "~> 0.12.0"},
            {:guardian_db, "~> 0.5"},

I'm trying to create jwt authentication according to documentation, the token gets created and saved into mongodb, but it can't fetch it back. Checking mongodb db logs, i found that query is wrong:

    "query" : {
        "find" : "tokens",
        "filter" : {
            "_id" : "16840477-68a5-44e7-9dfa-778f0cbed67c",
            "aud" : "User:577079cd26cb762b314d9c01"
        },
        "ntoreturn" : 1000,
        "sort" : {

        }
    },

The problem here is that _id is autogenerated and looks like:

> db.tokens.find().pretty()
{
    "_id" : ObjectId("5772ded626cb767520899d2c"),
        ...

The _id in the query is actually a jti field.
This might me an issue with mongodb_ecto or something else, since i see this line here:

    @primary_key {:jti, :string, autogenerate: false }

Please advice

What is this compile error?

== Compilation error on file lib/guardian_db.ex ==
** (FunctionClauseError) no function clause matching in Keyword.get/3
(elixir) lib/keyword.ex:150: Keyword.get(nil, :schema_name, nil)
lib/guardian_db.ex:25: (module)
lib/guardian_db.ex:18: (module)

Bump Postgrex to version 0.10

Ecto >= 1.1 (https://hex.pm/packages/ecto/1.1.0) uses Postgrex 0.10 which causes the dependency resolution to fail.

Looking up alternatives for conflicting requirements on postgrex
  Activated version: 0.9.1
  From mix.exs: >= 0.0.0
  From mix.lock: 0.9.1
  From ecto v1.1.1: ~> 0.10
  From guardian_db v0.3.0: ~> 0.9.1

** (Mix) Hex dependency resolution failed, relax the version requirements or unlock dependencies

Revoking Token thats already been removed throws error rather than returning error

We've run into a condition where a request to refresh a token was replayed which resulted in duplicate requests processed at the same time. The first one succeeded and the second one failed with an Ecto.StaleEntryError when trying to revoke and delete the token. Instead of doing a delete on the Model could we just do a delete by the value of the primary key so we can return an {:error} instead of throwing an error?
Similar to:

|> Guardian.DB.repo().delete_all(prefix: prefix())

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.