Using Omniauth with Rails + React - CORS issue - ruby-on-rails

I am trying to use omniauth for authentication in my rails/react app using the shopify strategy.
After sending the user to the omniauth path:
SessionsController
def authenticate
redirect_to "/auth/shopify?shop=#{params[:shop]}"
end
Omniauth is sending a 302 redirect to my browser:
Rails Output
(shopify) Setup endpoint detected, running now.
(shopify) Request phase initiated.
127.0.0.1 - - [29/Mar/2018:15:02:40 DST] "GET /auth/shopify?shop=xxx.myshopify.com HTTP/1.1" 302 280
http://localhost:8082/ -> /auth/shopify?shop=xxx.myshopify.com
After that happens, a CORS error appears in my browser:
Failed to load https://x.myshopify.com/admin/oauth/authorize?client_id=x&redirect_uri=http%3A%2F%2Flocalhost%3A3000%2Fauth%2Fshopify%2Fcallback&response_type=code&scope=read_products&state=x:
Redirect from 'https://x.myshopify.com/admin/oauth/authorize?client_id=x&redirect_uri=http%3A%2F%2Flocalhost%3A3000%2Fauth%2Fshopify%2Fcallback&response_type=code&scope=read_products&state=x'
to 'https://x.myshopify.com/admin/auth/login' has been blocked by CORS policy:
No 'Access-Control-Allow-Origin' header is present on the requested resource.
Origin 'null' is therefore not allowed access.
This causes my fetch request to fail without anything in the error object.
How can I prevent this error?

Related

Why google oauth flow is failing when initiated from frontend, but seems to work if I initiate from backend directly?

I have a Flash backend using flask-dance in order to allow a web app to authenticate users with Google provider.
In my local dev environment, the backend runs from https://localhost:5000, while my local frontend is at https://local.mydomain.com
I have a backend endpoint at https://localhost:5000/login/google which redirects the user to the Google OAuth flow:
#app.route('/login/<provider>')
def login(provider: str):
# here we store the page the user has come from with the referrer value
session["return_to"] = request.referrer
if provider == 'google':
return redirect(url_for("google.login"))
return False
If I access this URL directly in the browser, I'm redirected to Google and the OAuth flow completes successfully.
If, however, I add a button on the frontend that redirects to that URL, the OAuth flow fails midway and the browser prints the following errore:
Access to XMLHttpRequest at 'https://accounts.google.com/o/oauth2/auth?response_type=code&client_id=580945975384-0mqduo9k8dchc0ho7tnd7g6ejo70jrlb.apps.googleusercontent.com&redirect_uri=https%3A%2F%2Flocalhost%3A5000%2Fauth%2Fgoogle%2Fauthorized&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.email+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.profile+openid&state=tWt5b2pkp0jfjxtXD8aHlMwsKyuCJw' (redirected from 'https://localhost:5000/login/google') from origin 'https://local.mydomain.com' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
index.js:1 Error: Network Error
at createError (createError.js:16)
at XMLHttpRequest.handleError (xhr.js:117)
xhr.js:210 GET https://accounts.google.com/o/oauth2/auth?response_type=code&client_id=580945975384-0mqduo9k8dchc0ho7tnd7g6ejo70jrlb.apps.googleusercontent.com&redirect_uri=https%3A%2F%2Flocalhost%3A5000%2Fauth%2Fgoogle%2Fauthorized&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.email+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.profile+openid&state=tWt5b2pkp0jfjxtXD8aHlMwsKyuCJw net::ERR_FAILED 200
This is the failed request:
The Flask backend app has CORS enabled.
Why is this happening?
I suspect that running the backend locally from a different domain has something to do with it, but I couldn't quite figure out exactly what is going on and how to fix this.
The Google OAuth URL you request (https://accounts.google.com/o/oauth2/auth) is the starting point for their authentication process - it requires a full browser - it needs to display a credentials form, consent and then to redirect the browser back to your application. That's why you cannot use XMLHttpRequest for accessing it.
Your backend CORS settings cannot help it - Google would have to enable it on their endpoint, but it still would not work for the reasons mentioned before.

Rack cors error in full stack application

I am using react for the front end and Ruby on Rails for the back end. I am using version 2.6.1 for ruby on rails.
When I started my application I am getting an error saying...
"Access to fetch at 'http://localhost:3000/profile' from origin 'http://localhost:3001' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled."

Unable to obtain configuration from discovery endpoint on IIS when hostnames are used

I have a Javascript SPA that uses access tokens to talk to a backend API / Auth server. I'm using OpenIddict and JWT Bearer authentication on our combined API / Authorization server. We are using the Implicit flow.
For the time being, I am not using SSL - all requests are just http.
Everything has been configured and works correctly on my dev machine. When I publish these 2 sites to IIS everything still works fine when using an IP addresses for the 2 websites that are set up (there is 1 website for the Javascript SPA, and 1 website for the API / Auth server).
So basically I have 2 websites at the same IP address running on 2 different ports:
1) SPA 192.168.1.50:3000
2) AuthServer 192.168.1.50:5959
Now I want to enable hostnames for these sites. I now have edited the IIS bindings in order to bind these 2 sites to a host name like so:
1) SPA app.mycompany:3000
2) AuthServer app.mycompany:5959
When I do this, I am getting a message about not being able to access the .well-known/openid-configuration endpoint and am getting a JWT Bearer exception when trying to hit the UserInfo endpoint.
I can hit my SPA, get redirected to the Auth Server's login page and then successfully login. By looking at the web requests in Fiddler I see that I can hit the authorize end point and now have an access_token. As soon as the discovery step happens though things break.
The discovery end point can't be found and then immediately after that the userinfo endpoint is prevented from being hit because the bearer authentication fails.
By examining my logs I can see that JWT Bearer token fails to validate on the the UserInfo endpoint.
When this discovery endpoint is requested:
app.mycompany:5959/.well-known/openid-configuration
This is the error message I am getting:
IDX10803: Unable to obtain configuration from: 'http://app.mycompany.com:5959/.well-known/openid-configuration
And in my logs this is what I'm seeing at the point where the UserInfo controller is requested:
2017-11-09 14:12:35.7510|1|INFO|Microsoft.AspNetCore.Hosting.Internal.WebHost|Request starting HTTP/1.1 OPTIONS http://app.mycompany:5959/connect/userinfo
2017-11-09 14:12:35.7510|1|DEBUG|Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware|OPTIONS requests are not supported
2017-11-09 14:12:35.7510|1|DEBUG|Microsoft.AspNetCore.Cors.Infrastructure.CorsService|The request is a preflight request.
2017-11-09 14:12:35.7510|2|DEBUG|Microsoft.AspNetCore.Cors.Infrastructure.CorsService|The request has an origin header: 'http://app.mycompany:3000'.
2017-11-09 14:12:35.7510|4|INFO|Microsoft.AspNetCore.Cors.Infrastructure.CorsService|Policy execution successful.
2017-11-09 14:12:35.7510|9|DEBUG|Microsoft.AspNetCore.Server.Kestrel|Connection id "0HL97NQJHQ576" completed keep alive response.
2017-11-09 14:12:35.7510|2|INFO|Microsoft.AspNetCore.Hosting.Internal.WebHost|Request finished in 6.2953ms 204
2017-11-09 14:12:35.7510|1|INFO|Microsoft.AspNetCore.Hosting.Internal.WebHost|Request starting HTTP/1.1 GET http://app.mycompany:5959/connect/userinfo
2017-11-09 14:12:35.7510|4|DEBUG|Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware|The request path /connect/userinfo does not match a supported file type
2017-11-09 14:12:35.7510|2|DEBUG|Microsoft.AspNetCore.Cors.Infrastructure.CorsService|The request has an origin header: 'http://app.mycompany:3000'.
2017-11-09 14:12:35.7510|4|INFO|Microsoft.AspNetCore.Cors.Infrastructure.CorsService|Policy execution successful.
2017-11-09 14:12:35.7510|0|DEBUG|OpenIddict.OpenIddictHandler|The default userinfo request handling was skipped from user code.
2017-11-09 14:12:35.7664|9|DEBUG|Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationHandler|AuthenticationScheme: Identity.Application was not authenticated.
2017-11-09 14:12:35.7664|1|DEBUG|Microsoft.AspNetCore.Routing.Tree.TreeRouter|Request successfully matched the route with name '(null)' and template 'connect/userinfo'.
2017-11-09 14:12:35.7664|1|DEBUG|Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker|Executing action ApiAuthServer.Controllers.UserinfoController.Userinfo (ApiAuthServer)
2017-11-09 14:12:35.7664|2|DEBUG|Microsoft.AspNetCore.Cors.Infrastructure.CorsService|The request has an origin header: 'http://app.mycompany:3000'.
2017-11-09 14:12:35.7664|4|INFO|Microsoft.AspNetCore.Cors.Infrastructure.CorsService|Policy execution successful.
2017-11-09
14:12:35.7664|3|ERROR|Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler|Exception occurred while processing message. IDX10803: Unable to obtain configuration from: 'http://app.mycompany:5959/.well-known/openid-configuration'.
If I navigate directly to app.mycompany:5959/.well-known/openid-configuration from outside the server in a browser, I can hit that discovery endpoint and see the json data. It works.
But if I try to access that endpoint from within the IIS server I get the same error message. I can't seem to access that on the IIS box. But if I remove the host name binding and go back to IP addresses, I can successfully hit the discovery endpoint even on the IIS box and the app works fine.
So I am really at a loss of what the problem is. Not sure if there is some IIS setting I need to tweak, or if this is a bug in the JWT Bearer middleware or if it is something to do with OpenIddict.
I just want to be able to use hostnames on IIS for my app(s)

OpenAM receives oAuth2 auth code, but doesnt request access token Invalid Session Id

I have implemented my own oAuth2 provider server (using the Grails spring security oAuth2 plugin) and am now trying to connect it to OpenAM.
When I try to log in, it redirects properly to my own login form and on succesfull authentication redirects back to OpenAM with the following url:
http://sso.my-domain.com/openam/XUI/#login/&realm=%myRealm&code=dPPg1g&state=rzhjjjl1wpmndz7zfh4gqm1r5k9xi2l
However, OpenAM says "Unable to login". The auth code is in the URL so it should be able to request an access token, so I went and did some debugging to find out that it doesnt even attempt to retrieve a token; relevant bits of logs follow:
from localhost_access_log:
[15/Dec/2015:11:29:17 +0100] "GET /MyOAuthProvider/oauth/authorize?client_id=openAm&scope=read&redirect_uri=http%3A%2F%2Fsso.my-domain.com%3A80%2Fopenam%2Foauth2c%2FOAuthProxy.jsp&response_type=code&state=rzhjjjl1wpmndz7zfh4gqm1r5k9xi2l HTTP/1.1" 200 901
[15/Dec/2015:11:29:18 +0100] "POST /MyOAuthProvider/oauth/authorize?client_id=openAm&scope=read&redirect_uri=http%3A%2F%2Fsso.my-domain.com%3A80%2Fopenam%2Foauth2c%2FOAuthProxy.jsp&response_type=code&state=rzhjjjl1wpmndz7zfh4gqm1r5k9xi2l HTTP/1.1" 302 -
As you can see, there is no call to /MyOAuthProvider/oauth/token, which is the token access point.
From /usr/share/tomcat7/openam/openam/debug/debug.log: http://pastebin.com/qivhR9JF (put on PasteBin because its a little too long)
When testing on local I was able to get the auth code and then the token just fine with calls from Postman, so that shouldnt be the problem.
Am I missing something here? Any help is appreciated
After digging around through the OpenAM debug log, I found out that it attempts to retrieve the token, but gets a "Connection refused". It seems the problem lied in a proxy and routing on my servers.
Since openAM and my oAuth provider run on the same Tomcat, changing the token (and user data) urls from sso.my-domain.com to localhost:8080 fixed the issue

OAuth2::Error with doorkeeper

Whenever I try to authenticate with doorkeeper provider, I always got the following error
invalid_grant: The provided authorization grant is invalid, expired, revoked, does not match the redirection URI used in the authorization request, or was issued to another client. {"error":"invalid_grant","error_description":"The provided authorization grant is invalid, expired, revoked, does not match the redirection URI used in the authorization request, or was issued to another client."}
I tried with other doorkeeper clients but still have the same error
Doorkeeper client:
https://github.com/doorkeeper-gem/doorkeeper-devise-client.git
http://dev.mikamai.com/post/112508735689/oauth2-on-rails-the-client-application
Doorkeeper provider:
https://github.com/doorkeeper-gem/doorkeeper-provider-app.git
Though downgrading to gem 'omniauth-oauth2', '~> 1.3.1' is a confirmed to be a solution, in Doorkeeper's Create-a-OmniAuth-strategy-for-your-provider Wiki Page it is mentioned that in your implementation of OmniAuth Strategy for Doorkeeper the following method should be present:
# https://github.com/intridea/omniauth-oauth2/issues/81
def callback_url
full_host + script_name + callback_path
end
There is long discussion in the referred omniauth-oauth2 issue #81
I personally faced the reported error when I was trying to test my Rails 5 Devise-based Doorkeeper Provider by using a Rails 5 Devise-based Client app to allow Provider's users connect their account on my client-app.
In absence of the mentioned method in my OmniAuth::Strategies::Doorkeeper
on front-end Devise OmniauthCallbacksController was flashing message Invalid Credentials and in the client-app server logs following error was seen:
Started GET "/users/auth/doorkeeper" for 127.0.0.1 at 2017-08-22 17:45:02 +0530
I, [2017-08-22T17:45:02.386866 #14535] INFO -- omniauth: (doorkeeper) Request phase initiated.
Started GET "/users/auth/doorkeeper/callback?code=1b833bcc09651f98b0424a7afb1e60bd50fdcc765daf7d499bcefb5554457187&state=c215fd707ecd71c6ad0f6b5e58fa0d2da7210d86946d41e3" for 127.0.0.1 at 2017-08-22 17:45:03 +0530
I, [2017-08-22T17:45:03.506424 #14535] INFO -- omniauth: (doorkeeper) Callback phase initiated.
E, [2017-08-22T17:45:03.523737 #14535] ERROR -- omniauth: (doorkeeper) Authentication failure! invalid_credentials: OAuth2::Error, invalid_grant: The provided authorization grant is invalid, expired, revoked, does not match the redirection URI used in the authorization request, or was issued to another client.
{"error":"invalid_grant","error_description":"The provided authorization grant is invalid, expired, revoked, does not match the redirection URI used in the authorization request, or was issued to another client."}
Processing by Users::OmniauthCallbacksController#failure as HTML
Parameters: {"code"=>"1b833bcc09651f98b0424a7afb1e60bd50fdcc765daf7d499bcefb5554457187", "state"=>"c215fd707ecd71c6ad0f6b5e58fa0d2da7210d86946d41e3"}
Redirected to http://localhost:5000/
Completed 302 Found in 0ms (ActiveRecord: 0.0ms)
So adding that method to the strategy can be considered as an alternate solution.
Thanks.
I solved it by downgrading omniauth-oauth2 gem version to 1.3.1 mentioned here - https://github.com/intridea/omniauth-oauth2/issues/81

Resources