Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Guardian.Plug.EnsureAuthenticated not working #194

Closed
qgadrian opened this issue Aug 30, 2016 · 7 comments
Closed

Guardian.Plug.EnsureAuthenticated not working #194

qgadrian opened this issue Aug 30, 2016 · 7 comments

Comments

@qgadrian
Copy link

qgadrian commented Aug 30, 2016

Hi, I was playing around with Guardian but can't make the plug Guardian.Plug.EnsureAuthenticated work within an api request.

Authentication seems to work fine, but maybe it's that the problem and not the plug itself. Every time I try to do a request to a controller using the plug, the error handler method unauthenticated is called.

router.ex

  pipeline :api do
    plug :accepts, ["json"]
    plug :fetch_session
    plug Guardian.Plug.VerifyHeader # Looks for token in authorization header
    plug Guardian.Plug.LoadResource # Makes the current resource available Guardian.Plug.current_resource(conn)
  end

  scope "/api", TestApp do
    pipe_through :api

    scope "/v1" do
      resources "/user", UsersController, only: [:create, :show, :delete, :update]

      resources "/sessions", SessionController, only: [:create, :delete]
    end
  end

config.exs

# Authentication token library config
config :guardian, Guardian,
  issuer: "TestApp",
  ttl: { 3, :days },
  verify_issuer: false,
  serializer: TestApp.GuardianSerializer

authentication controller

  def create(conn, %{"session" => session_params}) do
    case TestApp.Session.authenticate(session_params) do
      {:ok, user} ->
        Guardian.Plug.sign_in(conn, user)
        text conn, ""
      :error ->
        conn
        |> put_status(:unprocessable_entity)
        |> render("error.json")
    end
  end

authenticated ensured controller

plug Guardian.Plug.EnsureAuthenticated, handler: TestApp.SessionController

  plug :scrub_params, "user" when action in [:create, :update]
  plug :scrub_params, "id" when action in [:show, :delete]

  def delete(conn, %{"id" => id}) do
    user = Guardian.Plug.current_resource(conn)
    Logger.debug "Current logged user is #{inspect(user)}"

    case find_user_or_render_not_found(conn, id) do
      {:ok, user} ->
        Logger.debug "Deleting user #{inspect(user)}..."
        case Repo.delete(user) do
          {:ok, user} ->
            Logger.debug "Deleted user #{inspect(user)}"
            conn
            |> put_status(:ok)
            |> render(TestApp.SessionView, "delete.json")
          {:error, changeset} ->
            Logger.debug "Error deleting #{inspect(changeset)}"
        end
    end
  end

I'm sending the request with the Authorization request header with the jwt token. A log line in unauthenticated method shows the following:

[debug] Not authenticated request. Params: %{:reason => {:error, %CaseClauseError{term: {:error, {:badmatch, false}}}}, "id" => "5"}

The test project can be found here

Thank you

@qgadrian
Copy link
Author

I could make it work adding the realm to the plug in the router.ex

plug Guardian.Plug.VerifyHeader, realm: "TestApp"

Without explicitly declaring the realm, it just didn't work at all.

@hassox
Copy link
Member

hassox commented Sep 1, 2016

Hi @qgadrian. I usually use Bearer as the realm. If you don't declare a realm on your verify header plug it will assume

AUTHORIZATION: <jwt>

With the relam

AUTHORIZATION: <realm name> <jwt>

It's up to the client to use the correct form that the server is expecting.

@GildedHonour
Copy link

I want to create a helper method "current_user" and be able to use it in all templates, much like in Devise in Rails. There's a function "guardianplugensureauthenticated" Could anyone give me a pointer how to utilize it for that? There's no base controller in Phoenix where I can define current_user by calling "guardianplugensureauthenticated"

@qgadrian
Copy link
Author

qgadrian commented Sep 3, 2016

@hassox Using the realm name it works fine. I'll check why without declaring a real it just don't work (maybe there is a default real name?).

@GildedHonour you can use at your controller methods the current user and the claims for an authenticated session. Check the readme, there you can see that you can use this

def index(conn, params, user, claims) do # do stuff in here end

@GildedHonour
Copy link

GildedHonour commented Sep 4, 2016

@qgadrian that would work. But I also want to do that on a module level. Suppose, I want to restrict access to the whole controller UserDashboard for non authenticated users. It can be done via router.ex file?

Also I want to use "current_user" helper function in the main layout for which I'll need to create it somehow in a SharedView or LayoutView. How can I get access to user and claims from a View?

@qgadrian
Copy link
Author

qgadrian commented Sep 4, 2016

@GildedHonour You can use the plug Guardian.Plug.EnsureAuthenticated in your router.ex or in a controller, that's up to you.

I don´t know anything about views yet, I just started learning Elixir/Phoenix 5 days ago. You can ask at Stackoverflow that.

@keithalpichi
Copy link

keithalpichi commented Sep 5, 2016

@qgadrian I usually set the realm to "Bearer" like so: plug Guardian.Plug.VerifyHeader, realm: "Bearer".

How are you testing your controllers and sending requests? Are you sending valid JWT tokens through the "authorization" header?

@GildedHonour you can create a current_user helper function in a module then import it in the web/web.ex file under the view function like so:

  def view do
    quote do

      #...

      import YourApp.Router.Helpers
      import YourApp.ErrorHelpers
      import YourApp.Gettext
      import YourApp.YourViewHelpers #<-------------------------------------- HERE
  end

That way the helper functions are imported in all views. In that helper module you can define helper functions like so:

  def current_user(conn) do
    Guardian.Plug.current_resource(conn)
  end

  def logged_in?(conn) do
    Guardian.Plug.authenticated?(conn)
  end

Where in a view you'd access the resources like so current_user(@conn) and logged_in?(@conn).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants