OAuth 2.0 Using for Google Login: Getting Unknown Host Exception - oauth-2.0

I am trying to implement Google Login for my webapp Using OAuth 2.0 for Login. However, while performing the step 4 ie. "Exchange Code for Access Token and ID Token", when I perform a POST request for the access and ID token, I get the following exception along with the below stacktrace.
java.net.UnknownHostException: https://accounts.google.com/o/oauth2/token
at java.net.Inet4AddressImpl.lookupAllHostAddr(Native Method)
at java.net.InetAddress$1.lookupAllHostAddr(InetAddress.java:866)
at java.net.InetAddress.getAddressesFromNameService(InetAddress.java:1258)
at java.net.InetAddress.getAllByName0(InetAddress.java:1211)
at java.net.InetAddress.getAllByName(InetAddress.java:1127)
at java.net.InetAddress.getAllByName(InetAddress.java:1063)
at org.apache.http.impl.conn.DefaultClientConnectionOperator.resolveHostname(DefaultClientConnectionOperator.java:242)
at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:130)
at org.apache.http.impl.conn.AbstractPoolEntry.open(AbstractPoolEntry.java:150)
at org.apache.http.impl.conn.AbstractPooledConnAdapter.open(AbstractPooledConnAdapter.java:121)
at org.apache.http.impl.client.DefaultRequestDirector.tryConnect(DefaultRequestDirector.java:575)
at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:425)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:820)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:776)
at dispatch.classic.BlockingHttp$class.dispatch$classic$BlockingHttp$$execute(Http.scala:45)
at dispatch.classic.BlockingHttp$$anonfun$execute$1$$anonfun$apply$3.apply(Http.scala:58)
at dispatch.classic.BlockingHttp$$anonfun$execute$1$$anonfun$apply$3.apply(Http.scala:58)
at scala.Option.getOrElse(Option.scala:120)
at dispatch.classic.BlockingHttp$$anonfun$execute$1.apply(Http.scala:58)
at dispatch.classic.Http.pack(Http.scala:25)
at dispatch.classic.BlockingHttp$class.execute(Http.scala:53)
at dispatch.classic.Http.execute(Http.scala:21)
at dispatch.classic.HttpExecutor$class.x(executor.scala:36)
at dispatch.classic.Http.x(Http.scala:21)
at dispatch.classic.HttpExecutor$class.when(executor.scala:50)
at dispatch.classic.Http.when(Http.scala:21)
at dispatch.classic.HttpExecutor$class.apply(executor.scala:60)
at dispatch.classic.Http.apply(Http.scala:21)
Following are the details of the POST request:
import dispatch.classic._
val req = :/("https://accounts.google.com/o/oauth2/token").secure
val params = Map(
"code" -> code,
"client_id" -> googleClientId,
"client_secret" -> googleClientSecret,
"redirect_uri" -> googleAuthURI,
"grant_type" -> "authorization_code"
)
val res = parse(h(req << params as_str))
where,
code is the auth code returned in the pervious request to https://accounts.google.com/o/oauth2/auth [Step 2 over here ]
googleAuthURI is "https://localhost/portal/google/login" which is what I have specified in the Google API developer console.
Also I am using scala and dispatch to implement this.

Turns out it was a problem with how dispatch finds out the hostname from the request url. In this case
val req = :/("https://accounts.google.com/o/oauth2/token").secure
Dispatch interprets the hostname as "https://accounts.google.com/o/oauth2/token" which is not available and hence it throws an exception. To counter this we need to structure the req url as,
val req = :/("accounts.google.com"/"o"/"oauth2"/"token").secure

Related

Paw not finding access_token from OAuth proxy

I have a use-case where I need to spoof a white-listed Redirect URL locally when performing OAuth 2 authentication.
I'm running a very basic web-server coupled with a hosts file entry for the domain I'm spoofing. I'm able to correctly negotiate my tokens and return them to Paw, but Paw isn't picking up my access_token or refresh_token, it simply displays the raw response:
Here's my server code (with placeholders for sensitive data):
var http = require('http'),
request = require('request');
var PORT = 6109;
var server = http.createServer(function(req, res) {
var code = req.url.split('?')[1].split('=')[2];
request({
url: 'https://<access token URL>/oauth2/token?code=' + code,
method: 'POST',
form: {
'client_id': <client_id>,
'client_secret': <client_secret>,
'grant_type': 'authorization_code',
'redirect_uri': <spoofed redirect URL>
}
}, function(err, response, data) {
data = JSON.parse(data);
res.writeHead(200, {'Content-Type': 'application/json'});
res.write(JSON.stringify(data.result));
// I also tried this with the same end-result
// res.writeHead(200);
// res.write('access_token=' + data.result.access_token + '&token_type=' + data.result.token_type + '&refresh_token=' + data.result.refresh_token);
res.end();
});
});
server.listen(PORT, function() {
console.log('Server listening on port %d', PORT);
});
What am I missing? Why isn't Paw finding my tokens?
Here's my configuration for reference:
Some other noteworthy points:
The OAuth provider is non-standard and flubs quite a few things from the spec (my proxy exists in part to patch up the non-standard bits)
The domain for the Redirect URL is real, but the URL does not resolve (this is a part of the reason for the local hosts entry)
I'm not showing this part of the flow, but I am correctly completing the authorization step prior to being given the code value
I think you're probably confused between the Authorization URL and Access Token URL. When you're in Authorization Code grant type for OAuth 2, you're expected to have a user confirmation step in a web page (the Authorization URL).
Which makes me guess that instead, you're expecting instead to use the Password Grant or Client Credentials? Otherwise, if you want to use Authorization URL, you'll need to specify a webpage at the Authorization URL.
Note: I've tried your Node.js script in Paw using the two last grants I mentioned (Password Grant & Client Credentials), and it works nicely.
Update: Following the comments below, I understand more what you are doing. The Authorization Request should (if successful) return a 302 redirect response to the Redirect URL page, and append a code URL query param to it. It seems like you're returning a JSON response with the code instead, so Paw isn't catching it.
According to the OAuth 2.0 spec (RFC 6749), section *4.1.2. Authorization Response*, if granted, the code should be passed as a URL query param (i.e. a ?key=value param in the URL) to the Redirect URL when doing the redirection.
If the resource owner grants the access request, the authorization
server issues an authorization code and delivers it to the client by
adding the following parameters to the query component of the
redirection URI using the "application/x-www-form-urlencoded" format
Quoting the example from the spec, here's how the response of the Authorization Request should look like if it's a success (code is granted):
HTTP/1.1 302 Found
Location: https://client.example.com/cb?code=SplxlOBeZQQYbYS6WxSbIA
&state=xyz
I saw that the Redirect URL contains "my Spoofed Uri".
When we need to use authorization code flow, we provide the authorization code and redirect Uri.
When the URI you are providing does not match the URI saved for the client in Identity server, you will not be able to get the token as the URI does not match with the client authorization code.
For example : Consider client identity in the Identity server be:
Auth Code: "xyx"
Redirect Uri: "www.mylocalhost.com\xyz"
And in your example the combination you are providing is:
Auth Code: "xyx"
Redirect Uri: "<my spoofed uri>"
As these 2 wont match there will be no token received.
I believe if you use the correct URI that is registered with the client in the Identity server, you will be able to receive the token.

Check the "grant_type" parameter

I am using OAuth 2.0 for authorization according to this documentation :(https://developers.vendhq.com/documentation/oauth.html#oauth) and having this error:
"error": "invalid_request", "error_description": "The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed. Check the \"grant_type\" parameter."
Request
Method : POST
Content-Type: application/x-www-form-urlencoded
URL : https://{domain_prefix}.vendhq.com/api/1.0/token
Parameters :
code = {code}
client_id = {app_id}
client_secret = {app_secret}
grant_type = authorization_code
redirect_uri = {redirect_uri}
As per the RFC6749, section 4.1.3, the encoded body of a POST request should look like code={code}&client_id={app_id}&client_secret={app_secret}&grant_type=authorization_code&redirect_uri={redirect_uri}.
Example:
grant_type=authorization_code&code=SplxlOBeZQQYbYS6WxSbIA&redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb&client_id=CLIENT_ID_1234&client_secret=CLIENT_SECRET
Do not forget to encode the redirect Uri: http://foo.bar/ => http%3A%2F%2Ffoo.bar%2F
Concerning the authentication error, it may be because the authorization server do not support client secret in post request (or your client is not allowed to use it).
Then try to add the Authorization header with basic authentication scheme.
The value of this header is Basic {ENCODED_AUTHENTICATION} with {ENCODED_AUTHENTICATION} =base64(client_id + ':' + client_secret)
With this header, the client_id and client_secret in the post request have to be removed. Your request parameters become code={code}&grant_type=authorization_code&redirect_uri={redirect_uri}.
You will need to check the URL to which you are attempting to send your POST to. The service that you are attempting to contact does not exist or is currently unavailable.

Oauth LinkedIn error using Scribe (response status code: 403)

I've been using a Grails Oauth Plugin for LinkedIn authentication for a few months now without any issues; today we are seeing this error with no change to our existing codebase. I verified that the API keys and the scope were correct on the LinkedIn Developer site. Anyone know how to solve this issue?
Error
response status code: 403
response body: oauth_problem=Scope%20INVALID%20%3A%20r_contactinfo%2Br_basicprofile%2Br_emailaddress
This is a version of the request that is being sent by the Scribe lib:
using base64 encoder: CommonsCodec
base string is: POST&https%3A%2F%2Fapi.linkedin.com%2Fuas%2Foauth%2FrequestToken&oauth_callback%3Dhttps%253A%252F%252Flocalhost%253A8443%252Foauth%252Flinkedin%252Fcallback%26oauth_consumer_key%3Dxxxxxxxxxxxxx%26oauth_nonce%3Dxxxxxxxxxxxxxxxxx%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1431479305%26oauth_version%3D1.0%26scope%3Dr_contactinfo%252Br_basicprofile%252Br_emailaddress
signature is: xxxxxxxxxxxxxxxxxxxxxxx
appended additional OAuth parameters: { oauth_callback -> https://localhost:8443/oauth/linkedin/callback , oauth_signature -> xxxxxxxxxxxxxxxxxxxxxxxxxxx, scope -> r_contactinfo+r_basicprofile+r_emailaddress , oauth_version -> 1.0 , oauth_nonce -> xxxxxxxxxxx , oauth_signature_method -> HMAC-SHA1 , oauth_consumer_key -> xxxxxxxxxxxxxxxxxx , oauth_timestamp -> 1431479305 }
using Http Header signature
Linked has changed their API usage terms with special permission needed for "r_contactinfo"
See
https://developer.linkedin.com/support/developer-program-transition
And
https://developer.linkedin.com/support/developer-program-transition
So if your Oauth request required r_contactinfo previously you are going to see this error. The fix is to not request r_contactinfo unless you have the specific permission from Li - uncheck this on Li Developer Dashboard for your application.
r_basicprofile & r_emailaddress can still be retrieved.

BadRequest when calling ProcessUserAuthorization after requesting "plus.login" scope

I have problems while updating code to new scope. Currently I use userinfo.profile and everything works Ok.
According to Google+ OAuth 2.0 scopes new plus.me scope allows application to know who user is, and plus.login also gives additional access (to age, language, circles, ...).
If I replace userinfo.profile with plus.me - everything works Ok: method WebServerClient.RequestUserAuthorization authorizes user and ProcessUserAuthorization gives me a token.
But if I ask plus.login scope instead - Google adds additional query parameters to my callback and next call to WebServerClient.ProcessUserAuthorization fails , because implementation uses current rul to make new redirect_url, striping "known" parameters and leaving "new unknown" Google parameters. his redirect_url doesn't match on registered in Google Api Console and Google server returns 400 response.
Here is success response from authorization with plus.me scope (from NetOpenAuth.Messaging.Channel log):
Incoming HTTP request: GET http://localhost:40004/Me/LoginComplete?from=Google&state=TWXf6Zq3XYSlwyfCDt3GiQ&code=4/qC_KeuiykcVm1sayIyEdnBjiklxz.AoMfk5TqaXQcsNf4jSVKMpY-GxwThAI
After binding element processing, the received EndUserAuthorizationSuccessAuthCodeResponse (2.0) message is:
code: 4/qC_KeuiykcVm1sayIyEdnBjiklxz.AoMfk5TqaXQcsNf4jSVKMpY-GxwThAI
state: TWXf6Zq3XYSlwyfCDt3GiQ
from: Google
And here is (success) authorization response with plus.login scope:
Incoming HTTP request: GET http://localhost:40004/Me/LoginComplete?from=Google&state=26R-O3YN6u3-5EKIlJzFFw&code=4/zOoeVq8vec068x2-CyPq4PjPNtRT.osemzp8Zl7sQsNf4jSVKMpbcmWQThAI&authuser=0&prompt=consent&session_state=27ca4bd2e70d0721bc1fa781b900a558e59fe4c7..d409
After binding element processing, the received EndUserAuthorizationSuccessAuthCodeResponse (2.0) message is:
code: 4/zOoeVq8vec068x2-CyPq4PjPNtRT.osemzp8Zl7sQsNf4jSVKMpbcmWQThAI
state: 26R-O3YN6u3-5EKIlJzFFw
from: Google
authuser: 0
prompt: consent
session_state: 27ca4bd2e70d0721bc1fa781b900a558e59fe4c7..d409
Call for token (for plus.me scope) will be successful:
Prepared outgoing AccessTokenAuthorizationCodeRequestC (2.0) message for https://accounts.google.com/o/oauth2/token:
code: 4/qC_KeuiykcVm1sayIyEdnBjiklxz.AoMfk5TqaXQcsNf4jSVKMpY-GxwThAI
redirect_uri: http://localhost:40004/Me/LoginComplete?from=Google
grant_type: authorization_code
client_id: 175802076419.apps.googleusercontent.com
client_secret: ********
But with plus.login scope 3 new parameters (authuser, prompt, session_state) are transferred to redirect_url param:
Prepared outgoing AccessTokenAuthorizationCodeRequestC (2.0) message for https://accounts.google.com/o/oauth2/token:
code: 4/zOoeVq8vec068x2-CyPq4PjPNtRT.osemzp8Zl7sQsNf4jSVKMpbcmWQThAI
redirect_uri: http://localhost:40004/Me/LoginComplete?from=Google&authuser=0&prompt=consent&session_state=27ca4bd2e70d0721bc1fa781b900a558e59fe4c7..d409
grant_type: authorization_code
client_id: 175802076419.apps.googleusercontent.com
client_secret: ********
And as soon as this redirect_url does not match registered I receive error:
https://accounts.google.com/o/oauth2/token returned 400 BadRequest: Bad Request
OAuth2 spec says that params code and state are required in authorization response and says noting about adding other parameters. But it also says that
The client MUST ignore unrecognized response parameters
Does this mean that this is DNOA issue and not Google one?
May be DNOA must add nullable responseUri parameter to ProcessUserAuthorization and use it instead of guessing from current url...
What's the easiest workaround (except using Google library)?
Update:
Here is original request for /oauth
Prepared outgoing EndUserAuthorizationRequestC (2.0) message for https://accounts.google.com/o/oauth2/auth:
client_id: 175802076419.apps.googleusercontent.com
redirect_uri: http://localhost:40004/Me/LoginComplete?from=Google
state: TWXf6Zq3XYSlwyfCDt3GiQ
scope: https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/plus.me
response_type: code

Authenticated http request fails in FSI only

I'm making an authenticated request like this:
let url = "https://datafeeds.networkrail.co.uk/ntrod/CifFileAuthenticate?type=CIF_ALL_FULL_DAILY&day=toc-full"
let auth = "Basic " + (username + ":" + password |> Encoding.UTF8.GetBytes |> Convert.ToBase64String)
Http.Request(url, headers=["Authorization", auth])
Http.Request is from FSharp.Data
On a compiled F# application it works fine, but when running this on F# interactive, somehow the request sent is slightly different and I get this error:
System.Net.WebException: The remote server returned an error: (403) Forbidden.
<?xml version="1.0" encoding="UTF-8"?>
<Error><Code>SignatureDoesNotMatch</Code><Message>The request signature we calculated does not match the signature you provided. Check your key and signing method.</Message>
Looking under fiddler, that url returns a 302 that redirects to https://nr-datafeed-cif.s3.amazonaws.com/CIF_ALL_FULL_DAILY%2Ftoc-full.json?...
But under fsi, the subsequent requests goes to https://nr-datafeed-cif.s3.amazonaws.com/CIF_ALL_FULL_DAILY/toc-full.json?... instead.

Resources