riverrun / phauxth

Not actively maintained - Authentication library for Phoenix, and other Plug-based, web applications
409 stars 21 forks source link

Authenticate subsequent requests with token only (without user_id) #39

Closed acrolink closed 7 years ago

acrolink commented 7 years ago

I have noticed that authentication works for subsequent requests (after login) by sending authorization header and user_id as parameter.

1) Is it possible, taken also security considerations into account, to authenticate subsequent requests with authorization token only?

2) If user_id must be submitted with every subsequent request, how to obtain it from the server? On successful login, the user gets access_token only. Is it safe to return the user_id with that response also?

Thank you.

riverrun commented 7 years ago

The user_id is not sent directly in the headers - just the token is sent, and then the check_token function in Phauxth.Authenticate gets the user_id from the token and tries to access the database by using the Accounts.get function.

If you add the line IO.inspect conn to, for example, the index function in your user_controller, you can see what information, including the headers, is sent to the function.

Let me know if you have any further questions.

acrolink commented 7 years ago

If I make a GET request to a protected resource with authorization token in headers I get:

{
    "errors": {
        "detail": "You need to login to view this resource"
    }
}

Despite that the Phoenix back-end log says:

[info] user=7 message="user authenticated"

To make it work (get data from server), I have to send the authorization token header and append ?user_id=7 to the URL.

riverrun commented 7 years ago

Which route is this?

riverrun commented 7 years ago

Can you show me how you are authorizing the user?

acrolink commented 7 years ago

@riverrun

The route I am trying to GET after authenticating the user is /api/properties which is defined at the controller like this:

  import BetaWeb.Authorize
  action_fallback BetaWeb.FallbackController
  def action(conn, _), do: auth_action_id(conn, __MODULE__)

  def index(conn, _params, user) do
    properties = Properties.list_properties()
    render(conn, "index.json", properties: properties)
  end

I authenticate the user by POST the following data to /api/sessions:

{
    "session": {
        "email": "w@w",
        "password": "852852"
    }
}

And I get a response like this:

{"access_token":"SFMyNTY.eyJzaWduZWQiOjE1MDc5NjY1NjMxMRksImRhdGEiOjd9.GSqtxnnBGTjrvd00Z0P00UKmjXU2RZqYwDqNdd8szQo"}
riverrun commented 7 years ago

Try replacing auth_action_id with auth_action and see if that works.

riverrun commented 7 years ago

You can also try replacing the line def auth_action_id(%Plug.Conn{params: %{"user_id" => user_id} = params, in the authorize.ex file with def auth_action_id(%Plug.Conn{params: %{"id" => user_id} = params, (replace "user_id" with "id").

acrolink commented 7 years ago

Changing:

def action(conn, _), do: auth_action_id(conn, __MODULE__)

to: def action(conn, _), do: auth_action(conn, __MODULE__)

Worked. The second suggestion did not. Thank you.

riverrun commented 7 years ago

I need to rethink the auth_action_id function. It works in the example todo app because the todo controller is nested within the user controller (so the "user_id" parameter is always available).

Does the auth_action function do what you want? It does not check for user id. It just makes sure that the user is authenticated.

acrolink commented 7 years ago

Yes, it works. I can get user data inside the controller (like id, which roles he has etc..). The important thing is that the authenticated user object is available, so action authorizations can be done based on roles he has.

riverrun commented 7 years ago

On this page, there is a basic example of customizing the auth_action function to allow for checking of roles.

Thanks for reporting the issue with the auth_action_id function. I will fix that tomorrow.