Closed niccolox closed 5 years ago
I should add, I was able to run the installer on an older version of phx
Yeah, only Ecto 2 is supported. I will update for Ecto 3 and Phoenix 1.4 support soon.
Reopening as I still need to add Phoenix 1.4 support to this issue.
cool, thanks, I just switched to head and will test it when its done
I'll need to test a bit and make a release, but you can try out #16. Just add {:phoenix_oauth2_provider, github: "danschultzer/phoenix_oauth2_provider", branch: "phoenix-1-4"}
to deps.
can close this, now am stuck at LoginWebsiteWeb.PhoenixOauth2Provider.AuthorizationController.init/1 is undefined (module LoginWebsiteWeb.PhoenixOauth2Provider.AuthorizationController is not available)
am trying to work out what I need to do with CustomUser and current_user to bootstrap the app, if anything
ok, I am going to stop now...
I am at http://localhost:4777/oauth/applications
UndefinedFunctionError at GET /oauth/applications function LoginWebsiteWeb.PhoenixOauth2Provider.ApplicationController.init/1 is undefined (module LoginWebsiteWeb.PhoenixOauth2Provider.ApplicationController is not available)
I need to stop for a while
I think I obviously need to do more with my CustomUser and the current user, but I am trying to work out (without an example) what exactly
am also guessing there might be some slight mismatch with the phx 1.4 umbrella generated structures and the generators of this hex
but, I am not sure, because I dont have a working example
I like the simplicity, but its been 2 days, not 2 minutes
I would be 2 mins if there was a working reference
thanks
I understand. Sounds like it’s just the routes that’s an issue, try this:
scope "/" do
pipe_through :oauth_public
oauth_routes :public
end
scope "/" do
pipe_through :protected
oauth_routes :protected
end
I suspect that the scope is the issue, and looks like the readme is wrong. I haven’t maintained this project well since there’s been virtually no developers using it 😀
ok, above worked (or at least progressed me)
now, I am at the current user / resource owner
Resource owner was not found with :current_user assigns
You will have to make sure users are authenticated, assuming you use Pow, you should add the following to your protected pipeline:
pipeline :protected do
plug Pow.Plug.RequireAuthenticated,
error_handler: Pow.Phoenix.PlugErrorHandler
end
so, I can have Pow, Pow Assent and Phoenix Oauth2 Provider in the same app?
I thought it was a client (Pow, Pow Assent) <> Oauth2 server split?
Also, with a default Pow setup you should just update the oauth2 provider config with: resource_owner: MyApp.Users.User
This is assuming you have a server with users, and want to permit third party access (e.g. mobile app). Pow/PowAssent is for registration and authentication of users on the server and OAuth2 provider is for third party API access.
so, my_website_com can have Pow, Pow Assent and Oauth2 provider in one app?
and other apps, oauth against my_website_com ?
Exactly. You could also have my_other_website_com with separate user schema using Pow and PowAssent to auth to your server app. Also, you only need PowAssent on your server app if you are going to permit users to register using some third party provider, e.g. github or facebook.
ok, thats how I hoped/assumed it all worked, but hit implementation issues
am getting close
now,
http://localhost:4453/oauth/authorize
flash not fetched, call fetch_flash/2
[error] #PID<0.504.0> running MyWebsiteWeb.Endpoint (connection #PID<0.503.0>, stream id 1) terminated
Server: localhost:4453 (http)
Request: GET /oauth/authorize
** (exit) an exception was raised:
** (ArgumentError) flash not fetched, call fetch_flash/2
(phoenix) lib/phoenix/controller.ex:1290: Phoenix.Controller.get_flash/1
(phoenix) lib/phoenix/controller.ex:1304: Phoenix.Controller.get_flash/2
(my_Website_com) lib/my_Website_com_web/templates/phoenix_oauth2_provider/layout/app.html.eex:24: PhoenixOauth2Provider.LayoutView."app.html"/1
(phoenix) lib/phoenix/view.ex:399: Phoenix.View.render_to_iodata/3
(phoenix) lib/phoenix/controller.ex:729: Phoenix.Controller.__put_render__/5
(phoenix) lib/phoenix/controller.ex:746: Phoenix.Controller.instrument_render_and_send/4
(phoenix_oauth2_provider) lib/phoenix_oauth2_provider/web/controllers/authorization_controller.ex:1: PhoenixOauth2Provider.AuthorizationController.action/2
(phoenix_oauth2_provider) lib/phoenix_oauth2_provider/web/controllers/authorization_controller.ex:1: PhoenixOauth2Provider.AuthorizationController.phoenix_controller_pipeline/2
(my_Website_com) lib/my_Website_com_web/endpoint.ex:1: MyWebsiteWeb.Endpoint.instrument/4
(phoenix) lib/phoenix/router.ex:275: Phoenix.Router.__call__/1
(my_Website_com) lib/my_Website_com_web/endpoint.ex:1: MyWebsiteWeb.Endpoint.plug_builder_call/2
(my_Website_com) lib/plug/debugger.ex:122: MyWebsiteWeb.Endpoint."call (overridable 3)"/2
(my_Website_com) lib/my_Website_com_web/endpoint.ex:1: MyWebsiteWeb.Endpoint.call/2
(phoenix) lib/phoenix/endpoint/cowboy2_handler.ex:34: Phoenix.Endpoint.Cowboy2Handler.init/2
(cowboy) /Users/devekko/Projects/my_Website_com/deps/cowboy/src/cowboy_handler.erl:41: :cowboy_handler.execute/2
(cowboy) /Users/devekko/Projects/my_Website_com/deps/cowboy/src/cowboy_stream_h.erl:296: :cowboy_stream_h.execute/3
(cowboy) /Users/devekko/Projects/my_Website_com/deps/cowboy/src/cowboy_stream_h.erl:274: :cowboy_stream_h.request_process/3
(stdlib) proc_lib.erl:249: :proc_lib.init_p_do_apply/3
Add :browser to the pipe_through:
scope "/" do
pipe_through :browser
oauth_routes :public
end
scope "/" do
pipe_through [:browser, :protected]
oauth_routes :protected
end
ok, that worked
now, do I create an outh app here http://localhost:4453/oauth/applications/new ?
where do I start?
what do the form inputs mean?
I added name: self callback urn:ietf:wg:oauth:2.0:oo scope blannk
[error] #PID<0.719.0> running MyWebsiteWeb.Endpoint (connection #PID<0.718.0>, stream id 1) terminated
Server: localhost:4453 (http)
Request: POST /oauth/applications
** (exit) an exception was raised:
** (UndefinedFunctionError) function nil.__schema__/1 is undefined
nil.__schema__(:primary_key)
(ecto) lib/ecto/changeset/relation.ex:140: Ecto.Changeset.Relation.change/3
(ecto) lib/ecto/changeset.ex:1132: Ecto.Changeset.put_change/7
(ecto) lib/ecto/changeset.ex:1339: Ecto.Changeset.put_relation/5
(ex_oauth2_provider) lib/ex_oauth2_provider/oauth_applications/oauth_applications.ex:244: ExOauth2Provider.OauthApplications.new_application_changeset/3
(ex_oauth2_provider) lib/ex_oauth2_provider/oauth_applications/oauth_applications.ex:145: ExOauth2Provider.OauthApplications.create_application/2
(phoenix_oauth2_provider) lib/phoenix_oauth2_provider/web/controllers/application_controller.ex:28: PhoenixOauth2Provider.ApplicationController.create/2
(phoenix_oauth2_provider) lib/phoenix_oauth2_provider/web/controllers/application_controller.ex:1: PhoenixOauth2Provider.ApplicationController.action/2
(phoenix_oauth2_provider) lib/phoenix_oauth2_provider/web/controllers/application_controller.ex:1: PhoenixOauth2Provider.ApplicationController.phoenix_controller_pipeline/2
(my_Website_com) lib/my_Website_com_web/endpoint.ex:1: MyWebsiteWeb.Endpoint.instrument/4
(phoenix) lib/phoenix/router.ex:275: Phoenix.Router.__call__/1
(my_Website_com) lib/my_Website_com_web/endpoint.ex:1: MyWebsiteWeb.Endpoint.plug_builder_call/2
(my_Website_com) lib/plug/debugger.ex:122: MyWebsiteWeb.Endpoint."call (overridable 3)"/2
(my_Website_com) lib/my_Website_com_web/endpoint.ex:1: MyWebsiteWeb.Endpoint.call/2
(phoenix) lib/phoenix/endpoint/cowboy2_handler.ex:34: Phoenix.Endpoint.Cowboy2Handler.init/2
(cowboy) /Users/devekko/Projects/my_Website_com/deps/cowboy/src/cowboy_handler.erl:41: :cowboy_handler.execute/2
(cowboy) /Users/devekko/Projects/my_Website_com/deps/cowboy/src/cowboy_stream_h.erl:296: :cowboy_stream_h.execute/3
(cowboy) /Users/devekko/Projects/my_Website_com/deps/cowboy/src/cowboy_stream_h.erl:274: :cowboy_stream_h.request_process/3
(stdlib) proc_lib.erl:249: :proc_lib.init_p_do_apply/3
Yeah, the fields should match the standard OAuth2 specs, you only need fill out the name and redirect uri. The local redirect uri is same setup as doorkeeper (rails) so you can get the token directly for manual tests instead of being redirected.
what would a standard phoenix_oauth2_provider be ?
The RFC specs: https://tools.ietf.org/html/rfc6749
This is the standard I’ve followed to build this library. Some things are also derrived from doorkeeper: https://github.com/doorkeeper-gem/doorkeeper
I am stuck
[debug] Processing with PhoenixOauth2Provider.ApplicationController.create/2
Parameters: %{"_csrf_token" => "QTwYJzFPDhcHXwVmNi5rLAl9eSoxNgAA4pAmd8tuWfnTOD2aPM1EyA==", "_utf8" => "✓", "oauth_application" => %{"name" => "test", "redirect_uri" => "urn:ietf:wg:oauth:2.0:oob", "scopes" => ""}}
Pipelines: [:browser, :protected]
[info] Sent 500 in 76ms
[error] #PID<0.513.0> running MyWebsiteWeb.Endpoint (connection #PID<0.512.0>, stream id 1) terminated
Server: localhost:4453 (http)
Request: POST /oauth/applications
** (exit) an exception was raised:
** (UndefinedFunctionError) function nil.__schema__/1 is undefined
my config
config :phoenix_oauth2_provider, PhoenixOauth2Provider,
repo: MyWebsite.Repo,
resource_owner: MyWebsite.User
config :phoenix_oauth2_provider, PhoenixOauth2Provider,
current_resource_owner: :current_user
defmodule MyWebsite.User do
use Ecto.Schema
use Pow.Ecto.Schema
use PowAssent.Ecto.Schema
schema "users" do
has_many :user_identities,
MyWebsite.UserIdentities.UserIdentity,
on_delete: :delete_all
pow_user_fields()
timestamps()
end
end
Are you signed in? It uses the current user in the conn, but looks like it is nil in yours. That route should be protected, and require authentication.
yes, am signed in
defmodule MyWebsiteWeb.Router do
use MyWebsiteWeb, :router
use Pow.Phoenix.Router
use PowAssent.Phoenix.Router
use PhoenixOauth2Provider.Router
pipeline :browser do
plug :accepts, ["html"]
plug :fetch_session
plug :fetch_flash
plug :protect_from_forgery
plug :put_secure_browser_headers
end
pipeline :api do
plug :accepts, ["json"]
end
pipeline :protected do
plug Pow.Plug.RequireAuthenticated,
error_handler: Pow.Phoenix.PlugErrorHandler
end
# Don't require CSRF protection
pipeline :oauth_public do
plug :put_secure_browser_headers
end
scope "/" do
pipe_through :browser
oauth_routes :public
end
scope "/" do
pipe_through [:browser, :protected]
oauth_routes :protected
end
scope "/" do
pipe_through :browser
pow_routes()
pow_assent_routes()
end
scope "/", MyFolkbotWeb do
pipe_through [:browser, :protected]
get "/", PageController, :index
end
# Other scopes may use custom stacks.
# scope "/api", MyFolkbotWeb do
# pipe_through :api
# end
end
Hmm, I’ll test this tomorrow to see whats wrong. The current user assign should be available, so not sure why oauth2 provider just receives a nil value.
<%= inspect @current_user.email %> gives my email thanks
Try delete the _build
folder and then compile it all again. I didn’t experience the issue if nil
, but I did experience a similar problem due to old build state.
ok, that worked
whats the redirect url for this provider ?
on github I use http://localhost:4453/auth/github/callback/
whats the phoenix_oauth2_provider equivalent?
phoenix_oauth2_provider
is just the sever/provider, and works the same way as on github. It is PowAssent that has a callback uri, just like with github. When you set it up in PowAssent it will be /auth/:provider/callback/
. The :provider
is whatever you call it in your config, e.g. the below config would have the callback uri /auth/example/callback/
:
ok, I Authorize the app and get
[error] #PID<0.505.0> running MyWebsiteWeb.Endpoint (connection #PID<0.484.0>, stream id 5) terminated
Server: localhost:4453 (http)
Request: GET /auth/my_website_com/callback?code=d0263e6f99e8c06878aedefa7006c5ad21a4c6dceacaf97ce4fde4a896a3f649
** (exit) an exception was raised:
** (PowAssent.CallbackCSRFError) CSRF detected
(pow_assent) lib/pow_assent/phoenix/controllers/authorization_controller.ex:117: PowAssent.Phoenix.AuthorizationController.handle_strategy_error/1
(pow_assent) lib/pow_assent/phoenix/controllers/authorization_controller.ex:1: PowAssent.Phoenix.AuthorizationController.action/2
(pow_assent) lib/pow_assent/phoenix/controllers/authorization_controller.ex:1: PowAssent.Phoenix.AuthorizationController.phoenix_controller_pipeline/2
(my_website_com) lib/my_website_com_web/endpoint.ex:1: MyWebsiteWeb.Endpoint.instrument/4
and
Headers:
cache-control: max-age=0, private, must-revalidate
date: Tue, 05 Feb 2019 02:49:10 GMT
server: Cowboy
content-length: 2513
content-type: text/markdown; charset=utf-8
x-request-id: 2m05frelbd8s10p0kk000201
Body:
"# Plug.CSRFProtection.InvalidCSRFTokenError at POST /oauth/token\n\nException:\n\n ** (Plug.CSRFProtection.InvalidCSRFTokenError) invalid CSRF (Cross Site Request Forgery) token, make sure all requests include a valid '_csrf_token' param or 'x-csrf-token' header\n (plug) lib/plug/csrf_protection.ex:233: Plug.CSRFProtection.call/2\n (my_website_com) lib/my_website_com_web/router.ex:7: MyWebsiteWeb.Router.browser/2\n (my_website_com) lib/my_website_com_web/router.ex:1: MyWebsiteWeb.Router.__pipe_through0__/1\n (phoenix) lib/phoenix/router.ex:270: Phoenix.Router.__call__/1\n (my_website_com) lib/my_website_com_web/endpoint.ex:1: MyWebsiteWeb.Endpoint.plug_builder_call/2\n (my_website_com) lib/plug/debugger.ex:122: MyWebsiteWeb.Endpoint.\"call (overridable 3)\"/2\n (my_website_com) lib/my_website_com_web/endpoint.ex:1: MyWebsiteWeb.Endpoint.call/2\n (phoenix) lib/phoenix/endpoint/cowboy2_handler.ex:34: Phoenix.Endpoint.Cowboy2Handler.init/2\n (cowboy) /Users/devekko/Projects/my_website_com/deps/cowboy/src/cowboy_handler.erl:41: :cowboy_handler.execute/2\n (cowboy) /Users/devekko/Projects/my_website_com/deps/cowboy/src/cowboy_stream_h.erl:296: :cowboy_stream_h.execute/3\n (cowboy) /Users/devekko/Projects/my_website_com/deps/cowboy/src/cowboy_stream_h.erl:274: :cowboy_stream_h.request_process/3\n (stdlib) proc_lib.erl:249: :proc_lib.init_p_do_apply/3\n \n\n## Connection details\n\n### Params\n\n %{\"client_id\" => \"d03fbe223785a496bb9125394f4db1ea35f7db73393d00f9fe6f01ba13ace4cc\", \"client_secret\" => \"22fe8282914c70c4fd8aba6621163bb6013473a53f8b910222c52fa2069328c6\", \"code\" => \"8682af643b047c2d85a0b73ea3ad4de5778358718ef83dd2e14fe4ffdfde21f2\", \"grant_type\" => \"authorization_code\", \"redirect_uri\" => \"http://localhost:4453/auth/my_website_com/callback\", \"response_type\" => \"code\", \"scope\" => \"user:read user:write\"}\n\n### Request info\n\n * URI: http://localhost:4453/oauth/token\n * Query string: client_id=d03fbe223785a496bb9125394f4db1ea35f7db73393d00f9fe6f01ba13ace4cc&client_secret=22fe8282914c70c4fd8aba6621163bb6013473a53f8b910222c52fa2069328c6&code=8682af643b047c2d85a0b73ea3ad4de5778358718ef83dd2e14fe4ffdfde21f2&grant_type=authorization_code&redirect_uri=http%3A%2F%2Flocalhost%3A4453%2Fauth%2Fmy_website_com%2Fcallback&response_type=code&scope=user%3Aread+user%3Awrite\n\n### Headers\n \n * connection: keep-alive\n * content-length: 0\n * host: localhost:4453\n * te: \n * user-agent: 0.1.0-rc.2\n\n### Session\n\n %{}\n"
(pow_assent) lib/pow_assent/phoenix/controllers/authorization_controller.ex:117: PowAssent.Phoenix.AuthorizationController.handle_strategy_error/1
(pow_assent) lib/pow_assent/phoenix/controllers/authorization_controller.ex:1: PowAssent.Phoenix.AuthorizationController.action/2
(pow_assent) lib/pow_assent/phoenix/controllers/authorization_controller.ex:1: PowAssent.Phoenix.AuthorizationController.phoenix_controller_pipeline/2
(my_website_com) lib/my_website_com_web/endpoint.ex:1: MyWebsiteWeb.Endpoint.instrument/4
(phoenix) lib/phoenix/router.ex:275: Phoenix.Router.__call__/1
(my_website_com) lib/my_website_com_web/endpoint.ex:1: MyWebsiteWeb.Endpoint.plug_builder_call/2
(my_website_com) lib/plug/debugger.ex:122: MyWebsiteWeb.Endpoint."call (overridable 3)"/2
(my_website_com) lib/my_website_com_web/endpoint.ex:1: MyWebsiteWeb.Endpoint.call/2
(phoenix) lib/phoenix/endpoint/cowboy2_handler.ex:34: Phoenix.Endpoint.Cowboy2Handler.init/2
(cowboy) /Users/devekko/Projects/my_website_com/deps/cowboy/src/cowboy_handler.erl:41: :cowboy_handler.execute/2
(cowboy) /Users/devekko/Projects/my_website_com/deps/cowboy/src/cowboy_stream_h.erl:296: :cowboy_stream_h.execute/3
(cowboy) /Users/devekko/Projects/my_website_com/deps/cowboy/src/cowboy_stream_h.erl:274: :cowboy_stream_h.request_process/3
(stdlib) proc_lib.erl:249: :proc_lib.init_p_do_apply/3
my
config :my_website_com, :pow_assent,
providers:
[
my_website_com: [
client_id: "REDACTED",
client_secret: "REDACTED",
strategy: PowAssent.Strategy.OAuth2,
site: "http://localhost:4453",
authorization_params: [scope: "user:read user:write"],
user_url: "http://localhost:4453/user"
]
]
router
defmodule MyWebsiteWeb.Router do
use MyWebsiteWeb, :router
use Pow.Phoenix.Router
use PowAssent.Phoenix.Router
use PhoenixOauth2Provider.Router
pipeline :browser do
plug :accepts, ["html"]
plug :fetch_session
plug :fetch_flash
plug :protect_from_forgery
plug :put_secure_browser_headers
end
pipeline :api do
plug :accepts, ["json"]
end
pipeline :protected do
plug Pow.Plug.RequireAuthenticated,
error_handler: Pow.Phoenix.PlugErrorHandler
end
# Don't require CSRF protection
pipeline :oauth_public do
plug :put_secure_browser_headers
end
scope "/" do
pipe_through :browser
oauth_routes :public
end
scope "/" do
pipe_through [:browser, :protected]
oauth_routes :protected
end
scope "/" do
pipe_through :browser
pow_routes()
pow_assent_routes()
end
scope "/", MyWebsiteWeb do
pipe_through [:browser, :protected]
get "/", PageController, :index
end
# Other scopes may use custom stacks.
# scope "/api", MyWebsiteWeb do
# pipe_through :api
# end
end
State is not carried over for some reason. I'll do a manual test to see what's going wrong.
Ok, so you need to add a new pipeline without :protect_from_forgery
. You already have :oauth_public
in your pipeline, so you can just use that one (you probably need to add plug :fetch_session
to it). Use that instead of :browser
for your public oauth routes.
defmodule MyWebsiteWeb.Router do
use MyWebsiteWeb, :router
use Pow.Phoenix.Router
use PowAssent.Phoenix.Router
use PhoenixOauth2Provider.Router
pipeline :browser do
plug :accepts, ["html"]
plug :fetch_session
plug :fetch_flash
plug :protect_from_forgery
plug :put_secure_browser_headers
end
pipeline :api do
plug :accepts, ["json"]
end
pipeline :protected do
plug Pow.Plug.RequireAuthenticated,
error_handler: Pow.Phoenix.PlugErrorHandler
end
# Don't require CSRF protection
pipeline :oauth_public do
plug :put_secure_browser_headers
end
scope "/" do
pipe_through :oauth_public
oauth_routes :public
end
scope "/" do
pipe_through [:browser, :protected]
oauth_routes :protected
end
scope "/" do
pipe_through :browser
pow_routes()
pow_assent_routes()
end
scope "/", MyWebsiteWeb do
pipe_through [:browser, :protected]
get "/", PageController, :index
end
# Other scopes may use custom stacks.
# scope "/api", MyWebsiteWeb do
# pipe_through :api
# end
end
Then you'll need to have a /user
endpoint ready. You should set the API endpoint(s) up to use the following plugs:
plug ExOauth2Provider.Plug.VerifyHeader
plug ExOauth2Provider.Plug.EnsureAuthenticated
Then you can gather the user by calling ExOauth2Provider.Plug.current_resource_owner(conn)
. E.g. like this:
def index(conn, _params) do
user = ExOauth2Provider.Plug.current_resource_owner(conn)
json(conn, %{id: user.id, email: user.email})
end
v0.5.0
has been released!
ok, I've worked my way through setup of Pow and Pow Assent on a new new phx 1.4 app
I assume I can also install this oauth provider into the same app? or this the problem?
or is it ecto 3 compatibility?
my mix
looks similar to https://github.com/ueberauth/guardian_db/issues/93
is this an ecto 3 thing?