Facebook PHP SDK fails to obtain token if redirect URL has the code parameter - facebook-php-sdk

I am attempting OAuth authentication using the Facebook PHP SDK v5.6.1.
When the browser returns to the redirect URL, I am unable to exchange the authorization code for an access token. Instead I get a redirect_uri_mismatch error:
Invalid redirect: https://.../ callback does not match one of the registered values.
(The text may not be exact because it had to be translated)
I debugged the Facebook SDK and found that the cause of this error is the code parameter passed back on the request URL. Normally the SDK infers the redirect URL from the PHP request, but when I manually supply the redirect URL to the SDK without the code parameter then the token exchange succeeds.
My goal, is to upgrade the SDK from an older version with a minimum of code changes, so I would like to avoid manually supplying the redirect URL if possible.
Inside the getAccessToken SDK method, the SDK takes care to remove the state parameter from the URL, but does nothing about removing the code parameter, which evidently needs to be removed.
In my app settings for Facebook Login I have strict mode switched off.
What else should I do to make the request URL functional as the redirect URL?
Something must be off because I don't see anyone else having an issue with this.

I carefully compared the mismatched url's and found one to be erroneous. The protocol said https but it also had port 80 specified. Turns out my apache reverse proxy headers were misconfigured.
RequestHeader set X-Forwarded-Proto 'https'
RequestHeader set X-Forwarded-Host 'hostname'
RequestHeader set X-Forwarded-Port '443'

Related

WooCommerce - Auto generating API keys using our Application Authentication Endpoint give 401 Invalid URL error

I'm attempting to use the REST API provided by WooCommerce to generate the Customer Secret and Customer Key values so that it could be used to invoke other WooCommerce REST APIs. I referred the documentation about generating the key values and managed to get it working using a mock endpoint in Postman used for the call_back URL in the API as mentioned in the document.
I created a POST service in my backend server and managed to setup a SSL certificate in the local environment with a domain mapped in hosts file in /etc directory. I ran the backend service and invoked the callback url through Postman and it worked. Then I used that as the call_back URL in the actual WooCommerce Auth endpoint to programatically generate the keys and save it in my DB. But I'm getting
"Access Denied" - Error: A valid URL was not provided..
When I checked the browser through devtools -> network noticed that there is a 401 Unauthorize error.
Here is the sample GET URL that is uesd for WooCommerce API key generation
http://localhost/woocommerce/wc-auth/v1/authorize?app_name=<SOME_NAME>&scope=read_write&user_id=36&return_url=http://localhost/woocommerce/&callback_url=https://foo.bar.dev:44329/api/services/app/woo_commerce_auth/6/callback
callback_url = https://foo.bar.dev:44329/api/services/app/woo_commerce_auth/6/callback
When the callback_url is a mock url generated using Postman it works fine
callback_url = https://513ca6ab-db16-4635-8d0b-9159e3b1e187.mock.pstmn.io/api/services/app/woo_commerce_auth/6/callback
Any clue why this happens, I could not find a way to troubleshoot this issue. Appreciate the help.
Hi posting this for future reference, and hope it would help others who face this problem as well.
Things to keep in mind when setting the callback_url,
Non HTTPS URL endpoint are not allowed.
URL should not be a localhost url (e.g localhost/callback would give an invalid URL error)
URL should not contain port number (e.g localhost:4320/callback or foo.bar.dev:4892/callback are invalid)
Callback URL should be a POST url
If an error such as Error: An error occurred in the request and at the time were unable to send the consumer data. is given after checking all the above check the backend service code related to the callback_url (I had a 500 server error which triggered this, it was not a WooCommerce issue)
Also a tool such as ngrok would be really helpful to setup an HTTPS endpoint in your local environment to test this.

How to access Firebase from http://localhost:3000

I'm developing a React app, and I get this error when trying to sign in to Firebase using their email auth provider.
Failed to load https://www.googleapis.com/identitytoolkit/v3/relyingparty/verifyPassword?key=.....:
Response to preflight request doesn't pass access control check: The
'Access-Control-Allow-Origin' header has a value 'https://localhost:3000'
that is not equal to the supplied origin. Origin 'http://localhost:3000'
is therefore not allowed access.
(Notice the https on line 3 versus http on line 4)
It looks like they changed Access-Control-Allow-Origin from *, to the https version of whatever domain you're calling from?
Does this mean I now need to configure my React app to run as https://localhost:3000?
You want to create a .env file in the root of your project and set HTTPS=true. This will launch your app using a self signed certificate.
Take a look at the advanced configuration options of create-react-app here
https://github.com/facebook/create-react-app/blob/master/packages/react-scripts/template/README.md#advanced-configuration
If you need more control over the certificate and do not want to eject. Take a look at react-app-rewired (https://github.com/timarney/react-app-rewired). You can config the devServer to use a custom certificate using the Extended Configuration Options here (https://github.com/timarney/react-app-rewired#extended-configuration-options)

What does a JWT cookie need to look like to work with NGINX modules?

I have been using NGINX as a reverse proxy and recently decided I needed to add authentication to a route on a website. I realised that there area multiple NGINX modules that could allow me to handle the authentication through NGINX (see links below). So, I build a single-sing-on login page that integrates auth0 to test how this would work.
All modules are similar and allow you to specify an auth_jwt_key (for validation of the JWT) as well as a variable to where the JWT (auth_jwt) is stored. I decided to store the JWT in a cookie.
Unfortunately, I can not get the validation through NGINX to work and keep seeing a 401 unauthorized return code.
Here is the part of the flask app, where I am handling the auth0 login and storing the JWT into a cookie:
#app.route('/callback')
def callback_handling():
token = auth0.authorize_access_token()
response = redirect('/dashboard')
response.set_cookie('lt_jwt', value=token.get('id_token'), max_age=token.get('expires_in'))
return response
Can you see something wrong with this? The resulting cookie looks something like this (I removed most of it for readability): lt_jwt eyJ0eX[...]SkRNZyJ9.eyJnaXZ[...]kzNDV9.d3Tzr[...]NzbA staging-auth0-login.scapp.io / 9/13/2018, 1:55:45 PM 1.03 KB
I can put the cookie value into jwt.io and decode it properly, but my problem is that the mentioned NGINX modules have issues decoding it.
Here is an example NGINX config, where I am setting up the authentication:
location = /dashboard {
auth_jwt_key "AUTH0_CLIENT_SECRET";
auth_jwt $cookie_lt_jwt;
root /usr/src/lt/nginx;
try_files /dashboard.html =404;
}
Basically, I never get to see dashboard.html and always get the 401 unauthorized. The NGINX error.log shows that decoding the JWT failed: [warn] 64#64: *23 JWT: failed to parse jwt, which in this case is an error log from the custom nginx module I used:
// Validate the jwt
if (jwt_decode(&jwt, jwt_data, conf->jwt_key.data, conf->jwt_key.len))
{
ngx_log_error(NGX_LOG_WARN, r->connection->log, 0, "JWT: failed to parse jwt");
return NGX_HTTP_UNAUTHORIZED;
}
Reference: https://github.com/maxx-t/nginx-jwt-module/blob/d9a2ece81ca66647f81fc2586b29b348af67f8aa/src/ngx_http_auth_jwt_module.c#L124
Unfortunately, it's not super easy to debug it, but I received a similar response from another custom NGINX module that I also tested: jwt_verify: error on decode: SUCCESS, which is a result of this code segment:
jwt_t* token;
int err = jwt_decode(&token, token_data, alcf->key.data, alcf->key.len);
if (err) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, errno,
"jwt_verify: error on decode: %s", strerror(errno));
return ngx_http_auth_jwt_set_realm(r, &alcf->realm);
}
Reference: https://github.com/tizpuppi/ngx_http_auth_jwt_module/blob/bf8ae5fd4b8e981b7683990378356181dee93842/ngx_http_auth_jwt_module.c#L247
So in both cases jwt_decode is called and fails (even though it's error code apparently is SUCCESS).
The reason I am asking here is that I feel I might be doing something conceptually wrong here:
formatting the cookie (I have seen jwt cookies looking like this:
Bearer eyJ0eX[...]SkRNZyJ9.eyJnaXZ[...]kzNDV9.d3Tzr[...]NzbA
assuming that an auth0 generated token can be used this way
...?
Please let me know if you have any insight or good working example with NGINX + auth0. I have read this article https://auth0.com/blog/use-nginx-plus-and-auth0-to-authenticate-api-clients/ by auth0 detailing how a very similar NGINX Pro module could be used, but I don't have access to that commercial module.
To answer the main question: The cookie should really contain only the JWT without any prefix. The python (flask) code in the question isn’t doing anything wrong and I was able to confirm with curl that you can in fact get authorized (with a valid JWT) stored in a cookie:
curl https://some.page.com/application --cookie "lt_jwt=eyJ0eX[...]SkRNZyJ9.eyJnaXZ[...]kzNDV9.d3Tzr[...]NzbA"
So what is the problem here - why can’t I authenticate in the browser, when it works via curl?
The reason was in the NGINX config, which required authentication to be disabled in the http context. This was essentially a bug in the NGINX module, which the developer managed to fix since.
Lesson learned: it's usually not your fault ;)

Determine current page url when using off box SSL termination

How can you determine the current request URL if using off box SSL termination?
E.g.
Browser has url httpS://yourserver/
SSL Termination decrypts and sends onto http://yourserver
IIS/ASP.NET receives request at http://yourserver
At (3) if you use Context.Request.Url, Page.Request.Url or Page.Request.RawUrl it show a url with a http protocol and not httpS
How do get the public httpS URL that was origionally used at (1) in this case?
The convention used for Microsoft Products is to add a header at the reverse proxy.
Front-End-Https : On
So you know the http url is really https.
You could also add in your own header containing the original URL if you did something like URL translation (e.g. something like "Original-Uri").
This page shows how to do this using IIS AAR as the reverse proxy, though in my testing I could only get headers to pass through if they are prefixed with HTTP_ (which is later stripped out).

Get the final destination after WP_Http redirects (WordPress)

I'm doing some requests to an API via WordPress, and the API uses SSL connections if they're turned on in the API settings. I'd like to determine whether SSL is turned on or off without having to ask the user if SSL is turned on on their account, and the API does a good job at redirecting, meaning
If I access http://api/endpoint and SSL is turned on, I'm redirected to https://api/endpoint
If I access https://api/endpoint and SSL is turned off, I'm redirected to http://api/endpoint
Now what I'd like to do is see whether a redirect happened or not and record that to my options so that the other requests are fired to the correct URL without any redirections.
So my question is: is there a way to determine the final destination after firing a WP_Http->request() when the request is being redirected?
I can't see any info about that in the response arrays, I only get to see the final response but I have no idea what URL that came from. What I can do is set the redirection parameter to 0 and catch the max redirects allowed error, but that's not bullet-proof, since I still don't know whether the redirect happened from http to https or simply another page under http.
I hope this all makes sense, let me know if you have any ideas.
Thanks!
~ K
check $response['headers'] - they may contain 'location' key.
It all depends on the HTTP library you are using.
See class-http.php(wp 3.0.1) file:
line 1393, http_api_curl action - curl handle available directly to catch anything.
fopen:
check lines 887-888, and $http_response_header variable.
also, try to override processHeaders function as it has an access to raw http headers.
The WP_Http class processes the headers and removes all but the last one. So you could do what jetdog described above. Check the original URL and compare it to the returned $response['headers']['location']. If it is different, than you know it redirected.

Resources