Closed guidedways closed 6 years ago
Bump
This is a serious issue at the moment and we've tried everything from rebooting, reauthenticating, revoking tokens and re-authorizing - nothing seems to be working for a majority of users. As I explained, this has only started happening recently with zero code changed. I'm not sure what's going on.
Have you read through https://github.com/e-mission/cordova-jwt-auth/issues/8 ? Googling the error message brings up several threads (some related to AppAuth, some not), that all seem to suggest the apps in question were suffering from same underlying type of issue).
I don't know what issue it could be though. I've gone through these threads, none apply. I'm spitting out the request here:
OAuth request was: <OIDAuthorizationRequest: 0x6080002bc3e0, request: https://accounts.google.com/o/oauth2/v2/auth?response_type=code&login_hint=some.email@gmail.com&scope=email%20https://www.googleapis.com/auth/calendar&code_challenge=WfaIB9e8N0q3CgRTVYg5JkY9C5WqgCtuZuvKwfQG2Cs&code_challenge_method=S256&redirect_uri=http://127.0.0.1:63557/&client_id=VALID-ID-HERE&state=KFi16jws7LWJ-u74X-pGf5xYDbN_azxV1jjriDz9gEo>
Error Domain=org.openid.appauth.oauth_token Code=-2 "invalid_request: Could not determine client ID from request." UserInfo={OIDOAuthErrorResponseErrorKey={
error = "invalid_request";
"error_description" = "Could not determine client ID from request.";
}, NSLocalizedDescription=invalid_request: Could not determine client ID from request., NSUnderlyingError=0x600000a59260 {Error Domain=org.openid.appauth.remote-http Code=400 "{
"error": "invalid_request",
"error_description": "Could not determine client ID from request."
}" UserInfo={NSLocalizedDescription={
"error": "invalid_request",
"error_description": "Could not determine client ID from request."
}}}}
As you can see, the request seems to be valid. It fails within the authStateByPresentingAuthorizationRequest
block. ClientID isn't null and the same request on another machine is working fine. Out of maybe 50,000 users, 5,000 are complaining, the rest aren't. Same app, same version, same code.
The error is coming from Google's OAuth2 authorization endpoint, so this isn't an issue with AppAuth itself. I'll nudge my contacts at Google to see if they can help you track down the issue.
@iainmcgin thank you! I've tried logging various parts of the OAuth flow and can't seem to fault it. There's no obvious signs of 'client ID' ever being null.
Could you share your client ID and the unredacted request URI with me? iainmcgin@gmail.com
Sending you an email now
Posting here for anyone else that stumbles upon this. As you can see the request clearly contains the client_id and seems valid (as I mentioned, this seems to be working for a majority of users out there, and I've been unable to reproduce this myself), while the response coming back states the request was invalid.
The user is taken to the 'Choose account' page, where they click on the Account name and then on Allow.
Request:
https://accounts.google.com/o/oauth2/v2/auth?response_type=code&login_hint=SOME.EMAIL@GMAIL.COM&scope=email%20https://www.googleapis.com/auth/calendar&code_challenge=KftVFZPoJJuUscf7omnwmseSc6aLhwRbdmjEHTMNYSo&code_challenge_method=S256&redirect_uri=http://127.0.0.1:51042/&client_id=CLIENT_ID&state=YWq1ODA4Vy9LLwouyW3Mzm8GuFPiO3FmTeI8kZAqDRA
Response:
<OIDTokenRequest: 0x6080002a7260, request: <URL: https://www.googleapis.com/oauth2/v4/token, HTTPBody: code=4/AABwNoueH1fWsKWcRokHyQBDMW6zrlH5GdGbO0HyJ0vVeLeysSxHyLJz_2ivPXREKUxLwr-xBUl4Bqo6KB8gw4A&code_verifier=KqSN7TvTf9g1SkU0eYIVs4ocHGGgYmX_VbxXNrzhbdg&redirect_uri=http://127.0.0.1:51042/&grant_type=authorization_code>> (<NSMutableURLRequest: 0x60800001b6a0> { URL: https://www.googleapis.com/oauth2/v4/token }) => <NSHTTPURLResponse: 0x62800002d6a0> { URL: https://www.googleapis.com/oauth2/v4/token } { status code: 400, headers {
"Cache-Control" = private;
"Content-Encoding" = gzip;
"Content-Length" = 105;
"Content-Type" = "application/json; charset=utf-8";
Date = "Thu, 05 Apr 2018 23:11:00 GMT";
Server = ESF;
Vary = "Origin, X-Origin, Referer";
"alt-svc" = "hq=\":443\"; ma=2592000; quic=51303432; quic=51303431; quic=51303339; quic=51303335,quic=\":443\"; ma=2592000; v=\"42,41,39,35\"";
"x-content-type-options" = nosniff;
"x-frame-options" = SAMEORIGIN;
"x-xss-protection" = "1; mode=block";
} } (server error: Error Domain=org.openid.appauth.remote-http Code=400 "{
"error": "invalid_request",
"error_description": "Could not determine client ID from request."
}" UserInfo={NSLocalizedDescription={
"error": "invalid_request",
"error_description": "Could not determine client ID from request."
}})
I wonder if Google broke their client_id check. I can see we were issued one in 2011, and the format isn't the same as the new ones they've been issuing lately. I'm going to try and generate a new client ID and see if that makes a difference.
Confirmed and fixed. This is an issue in AppAuth for Mac (this may also affect iOS users, given I've started seeing iOS users complain about the same thing in the past few days).
After two days of pulling my hair, I've finally got confirmation from affected users that it's fixed. The issue is subtle:
https://accounts.google.com/o/oauth2/v2/auth?response_type=code&login_hint=SOME.EMAIL@GMAIL.COM&scope=email%20https://www.googleapis.com/auth/calendar&code_challenge=KftVFZPoJJuUscf7omnwmseSc6aLhwRbdmjEHTMNYSo&code_challenge_method=S256&redirect_uri=http://127.0.0.1:51042/&client_id=CLIENT_ID&state=YWq1ODA4Vy9LLwouyW3Mzm8GuFPiO3FmTeI8kZAqDRA
Here's the issue. The Request URL created by AppAuth doesn't arrange the parameters in an orderly fashion and if the cliend_id
falls directly after redirect_uri
, it fails (I couldn't reproduce this, but users affected by this could, consistently).
127.0.0.1:51042/&client_id=CLIENT_ID
The &client_id
somehow was being treated as a parameter to the redirect_uri
(i.e. & after the / was being somehow treated as a parameter to the redirect_uri
and not the main request URL). So the solution was to move redirect_uri
to be the last parameter in the URL. I made slight modifications in OIDTokenRequest
, OIDAuthorizationRequest
and OIDURLQueryComponent
to be able to store the parameters in the correct order (the NSDictionary
returns keys in an unspecified order) and move redirect_uri
to be the last parameter to be added. This way the client_id
got properly parsed on its way back once the user clicks 'Allow' in Safari.
This does not explain why only a (large) portion of users experienced this issue (especially after the most recent security update from Apple), since I could not reproduce this on any of our test machines. However, this change alone has it fixed for all affected users.
So in comparison, the following rearrangement (authorisation request created by AppAuth) works:
https://accounts.google.com/o/oauth2/v2/auth?response_type=code&login_hint=SOME.EMAIL@GMAIL.COM&scope=email%20https://www.googleapis.com/auth/calendar&code_challenge=KftVFZPoJJuUscf7omnwmseSc6aLhwRbdmjEHTMNYSo&code_challenge_method=S256&client_id=CLIENT_ID&state=YWq1ODA4Vy9LLwouyW3Mzm8GuFPiO3FmTeI8kZAqDRA&redirect_uri=http://127.0.0.1:51042/
@WilliamDenniss Could you look at this if you get a chance?
I'm lost here. Would appreciate some help. The above changes worked, however now some (or possibly the same users) are reporting new failures. It seems it now fails when trying to refresh the token :(
OAuth: request failed: <OIDTokenRequest: 0x6040008a4c80, ClientID: XXXXXXX.apps.googleusercontent.com,
Scope: email https://www.googleapis.com/auth/calendar, Grant: refresh_token, request: <URL: https://www.googleapis.com/oauth2/v4/token,
HTTPBody:
grant_type=refresh_token&scope=email%20https://www.googleapis.com/auth/calendar&refresh_token=1/tYOwkNr9LpZQaqpggEtEkK5RXuL5W1pnzgR67EjyC7ip327srXjg5CsNrBK3uBhy>>
(<NSMutableURLRequest: 0x604000211740> { URL: https://www.googleapis.com/oauth2/v4/token }) => <NSHTTPURLResponse: 0x604001037a60>
{ URL: https://www.googleapis.com/oauth2/v4/token } { Status Code: 400, Headers {
"Cache-Control" = (
private
);
"Content-Encoding" = (
gzip
);
"Content-Length" = (
105
);
"Content-Type" = (
"application/json; charset=utf-8"
);
Date = (
"Sat, 07 Apr 2018 03:53:07 GMT"
);
Server = (
ESF
);
Vary = (
Origin,
"X-Origin",
Referer
);
"alt-svc" = (
"hq=\":443\"; ma=2592000; quic=51303432; quic=51303431; quic=51303339; quic=51303335,quic=\":443\"; ma=2592000; v=\"42,41,39,35\""
);
"x-content-type-options" = (
nosniff
);
"x-frame-options" = (
SAMEORIGIN
);
"x-xss-protection" = (
"1; mode=block"
);
} } (server error: Error Domain=org.openid.appauth.remote-http Code=400 "{
"error": "invalid_request",
"error_description": "Could not determine client ID from request."
}" UserInfo={NSLocalizedDescription={
"error": "invalid_request",
"error_description": "Could not determine client ID from request."
}})
I don't know what's going on suddenly. The client ID is being logged (I added it to the log above) which shows it exists. Why would it fail with the same error? Does it need to appear in the HTTPBody? But I'm using both ClientID and ClientSecret so these should have gone as part of the headers.
Could it be that the ClientID is still expected as a parameter in HTTPBody? I'm going to try doing that.
Okay so that worked partially. Below are logs from one of the users where it's failing:
OAuth: request failed: <OIDTokenRequest: 0x6080004b0800, ClientID: XXXX.apps.googleusercontent.com, Secret? 24 Scope: email https://www.googleapis.com/auth/calendar, Grant: refresh_token, request: <URL: https://www.googleapis.com/oauth2/v4/token, HTTPBody: grant_type=refresh_token&scope=email%20https://www.googleapis.com/auth/calendar&refresh_token=1/RVdkrdV17gsSDdPKvHR0xC3j_8YyH2GPxlcwLj-Hhfg&client_id=174767206656.apps.googleusercontent.com>> (<NSMutableURLRequest: 0x6080000176b0> { URL: https://www.googleapis.com/oauth2/v4/token }) => <NSHTTPURLResponse: 0x60000022da80> { URL: https://www.googleapis.com/oauth2/v4/token } { status code: 400, headers {
"Cache-Control" = private;
"Content-Encoding" = gzip;
"Content-Length" = 92;
"Content-Type" = "application/json; charset=utf-8";
Date = "Sat, 07 Apr 2018 12:47:46 GMT";
Server = ESF;
Vary = "Origin, X-Origin, Referer";
"alt-svc" = "hq=\":443\"; ma=2592000; quic=51303432; quic=51303431; quic=51303339; quic=51303335,quic=\":443\"; ma=2592000; v=\"42,41,39,35\"";
"x-content-type-options" = nosniff;
"x-frame-options" = SAMEORIGIN;
"x-xss-protection" = "1; mode=block";
} } (server error: Error Domain=org.openid.appauth.remote-http Code=400 "{
"error": "invalid_request",
"error_description": "client_secret is missing."
}" UserInfo={NSLocalizedDescription={
"error": "invalid_request",
"error_description": "client_secret is missing."
}})
The good news? It now complains client_secret
is missing! Which means passing client_id
in HTTPBody worked! I have no idea why the headers aren't being read by Google but clearly it needs the secret to be in the body too. I bet the next build I send them will work once I put that in there too.
But the question is - why? Here's a summary:
1) Users affected by this: in the thousands (I don't know the exact number, I'm guessing 5,000 - 10,000 based on reports in the past few days). There may be more that haven't yet reported the issue or simply aren't syncing with Google (we support other account types as well). The fact it's not just one in a million means it has to be affecting other apps / users out there.
2) The users seem to be on both 10.12 and 10.13. This is happening across hardware types: MacBook pros, Mac Pros, iMacs etc.
3) The app in question has been using the same code for several months. No part of the code was ever changed.
4) It seems to have started happening recently, maybe a week to 10 days ago.
A final note on this. Passing client_id
and client_secret
in HTTPBody fixed it for all those complaining. Now both authentication as well as token refresh seems to be working fine.
There seem to be multiple overlapping issues here, so let me try to clarify them:
When exchanging an authorization code for a refresh token, the client must assert its identity via a client ID or a client secret. For native apps we strongly discourage the use of static client secrets. Dynamic client secrets acquired through dynamic client registration are OK, but this is not common. If you don't know whether you're using static or dynamic client secrets, you're probably using static client secrets.
In a comment above, it was indicated that changing the order of the parameters passed as part of the authorization request was responsible for the loss of the client ID in the token request. This may be a URL encoding issue, we are investigating this.
If you are using a client secret to assert client identity, there are two options supported by the OAuth2 spec: providing it via an Authorization header, or providing it via the POST body (see Section 2.3 of the OAuth2 spec). Providing the client secret using a URL parameter is not supported by the spec - it is bad security practice to expose secrets via URL parameters.
So, in short: use public clients wherever possible, that is, those without a secret that assert identity using a client ID only. If you must use a client secret, prefer to send it using the Authorization header. Sending it as a parameter in the POST body is also acceptable.
We are now investigating to see if there is a real issue with escaping and/or parameter order on authorization requests.
Thanks Iain
Sending the secret using the Authorization header suddenly started failing a week ago. Sending it in the POST body works, but I'm not sure why it stopped working.
Like I said, I'm unable to reproduce this, and so are a lot of users, but whoever is experiencing this is consistently receiving failures. My tweaks above worked for them though.
If you do manage to reproduce a failure with the client secret set in the authorization header, please forward me the details so I can have Google investigate further.
I can't reproduce this. These are the steps I followed, and it worked for me. Can you try them with your client ID, and let me know what happens:
git clone git@github.com:openid/AppAuth-iOS.git
cd AppAuth-iOS/Examples/Example-macOS
pod install
open Example-macOS.xcworkspace
Modify these lines ONLY: https://github.com/openid/AppAuth-iOS/blob/b420522dae9f74d536ab81dfe9c5aaee7ecb0099/Examples/Example-macOS/Source/AppAuthExampleViewController.m#L28-L40
Issuer is "https://accounts.google.com", use your own client ID and secret.
Run the app and click "Authorize (HTTP Redirect)" (that's the one you are using).
Google uses client secrets with MacOS clients. When AppAuth is used with secrets, the client_id
is sent in the authorization request as a parameter (there is no secret sent with the authorization request). With the token request, both the client_id
and client_secret
are sent in it's sent as an Authorization header not as a URI parameter, and not in the body, here's the relevant code:
Generally I wouldn't recommend changing AppAuth's default behavior here unless you really know what you're doing.
To be clear: the only places you should supply the client_id and client_secret are in the appauth constructors that ask for them. They should NOT be added as additional parameters, and not manually added to any of the URIs.
So that's the general philosophy. Let me address two issues you raised directly:
Here's the issue. The Request URL created by AppAuth doesn't arrange the parameters in an orderly fashion and if the cliend_id falls directly after redirect_uri, it fails (I couldn't reproduce this, but users affected by this could, consistently).
The order of the parameters does not matter from an OAuth perspective, and I can't see any bugs in AppAuth's implementation. If what you're saying is true, then I believe it would indicate in a bug on the authorization server implementation.
However, I cannot reproduce any such bug.
Here's what my request looked like, it worked fine:
12:38:30: Authorization request: <OIDAuthorizationRequest: 0x6080000aad40, request: https://accounts.google.com/o/oauth2/v2/auth?response_type=code&login_hint=billd1600@google.com&scope=openid%20profile%20https://www.googleapis.com/auth/calendar&code_challenge=4IzIUHkvAQW7C4TwNwnhEBwVAG6kLRZlhXZ8xjjNkYc&code_challenge_method=S256&redirect_uri=http://127.0.0.1:64692/&client_id=392282445910-vhgkvbluf0e4qp91qenvbg4iatr783n8.apps.googleusercontent.com&state=barfsB3DzOo3pU27BAyv0cq7e4WKXQ5gFBvCrrA8Pw8>
I don't know what's going on suddenly. The client ID is being logged (I added it to the log above) which shows it exists. Why would it fail with the same error? Does it need to appear in the HTTPBody? But I'm using both ClientID and ClientSecret so these should have gone as part of the headers.
Could it be that the ClientID is still expected as a parameter in HTTPBody? I'm going to try doing that.
It looks like you tried adding the client_id
manually as an additional parameter at some point, as I can see this in one of your token endpoint requests. This is likely why you got the "missing secret" error. I wonder if when you were trying to debug this problem, it introduced more errors?
For the Token request, the client_id and secret should ONLY be present in the authorization header. Duplicating them in other places (e.g. in the request URI, or body) will lead to issues. If you need to change AppAuth's behavior, then you should fork it first. Google's token endpoint may accept these params in the body – but in that case, you shouldn't also be sending it in the header.
Here's how I recommend debugging this issue, and any future ones:
If you get bugs at 2., then it indicates an issue in either the library, or the server and should be reported. If you get bugs at 4. then it it may indicate an issue, or it could be that something you changed created the issue – worth further investigation.
I've had users reporting this issue for the last 7 - 10 days as well (after a year without issues).
Finally able to reproduce it myself, but it's entirely random, which makes it hard to track down.
How do I enable logging on this so I can see what's going on?
I haven't been able to reproduce this myself on any of our machines, so unfortunately don't know what else to add. All I know is that as we speak, we're getting dozens of users both on iOS and Mac report this for the previous version daily that's been out and about, using AppAuth for the last 2 years (without issues). It started happening 7-10 days ago and I bet we're not the only ones, although there's no solid way of reproducing this.
Fingers pointing to Google.
For us what worked was sending the client_id
and secret as part of the HTTP post body as the Authorization header no longer seems to be working.
Interesting - where did you add it in the code?
@alexobenauer search for "Confirmed and fixed." in my comments above.
@alexobenauer read all the way through, you'll need to make changes in a number of places for this to work. The order in which parameters are passed may not be relevant as that may just have been a fluke, but the real issue seems to have been client_id not being read from the authorization header. This became apparent when it worked mid-way through, but failed when requesting for a token refresh.
@guidedways thanks for the info. I'll dig in and see if I can do the same.
The randomness is what gets me - makes it very hard to test for, besides baffling. It does support the theory that the URL parameters may be getting shuffled though, since that would be random coming from a dictionary.
@guidedways could you post a snippet of the changes you've made for that workaround? I'd love to see if I'm getting close, especially since this is so difficult to test for.
@alexobenauer Start with the following change in OIDTokenRequest.m
's URLRequest
method:
if (_clientSecret) {
NSString *credentials = [NSString stringWithFormat:@"%@:%@", _clientID, _clientSecret];
NSData *plainData = [credentials dataUsingEncoding:NSUTF8StringEncoding];
NSString *basicAuth = [plainData base64EncodedStringWithOptions:kNilOptions];
NSString *authValue = [NSString stringWithFormat:@"Basic %@", basicAuth];
[httpHeaders setObject:authValue forKey:@"Authorization"];
// new
[bodyParameters addParameter:kClientIDKey value:_clientID];
[bodyParameters addParameter:kClientSecretKey value:_clientSecret];
} else {
[bodyParameters addParameter:kClientIDKey value:_clientID];
}
See if that alone fixes it for you.
@guidedways That's awesome - thank you! I'll send it to my testers today.
@alexobenauer my pleasure, would be interested in learning if that actually worked for you as well.
@guidedways I've heard back from a few so far with perfect results. That patch alone seems to be working!
I can't thank you enough for your help.
Hi Guys! I also encountered the discussed issue since about 2 weeks ago. I was able to constantly reproduce the failure during authorization process, and I can confirm that @guidedways solution above (adding client id and secret to bodyParameters) completely resolved the issue. I tested it several times and it was consistent. Thanks @guidedways !!
@WilliamDenniss I'm sorry I didn't get back to you, but I didn't know what to add given I haven't been able to reproduce this myself, yet as I explained, we're getting dozens of complaints daily from users on an older version of the app. The patch above seems to work for us (as well as for others).
This probably isn't an AppAuth issue per say, but clearly something changed at Google for the authorisation headers to break.
I don't know if this helps but some users reported that when they connect via a VPN, it works (i.e. the old version of the app). This may explain why some people are experiencing this and some aren't. Google may have broken this for a particular location(s) - I don't know. My fix above may not be ideal (I've left the authorisation header in there since I wasn't sure if this problem is going to re-appear and suddenly Google may start ignoring parameters passed in the body) but it's reduced a lot of headache, plus made some super-upset users very happy.
@guidedways is this update: [bodyParameters addParameter:kClientIDKey value:_clientID]; [bodyParameters addParameter:kClientSecretKey value:_clientSecret]; the only thing you did to resolve this issue?
@yankat that should be the only thing you need to fix this. The other changes I made in order to re-order the URL parameters isn't important, I don't think that was the reason it was failing. If that alone has fixed it then you're good to go :)
@guidedways thank you for taking the time to investigate this issue, and providing the workaround. We're still looking into the root cause, but you're right that the problem is to do with the Authorization header, and appears to be specific to Google. Your workaround is the right way to go.
My contacts at Google got back to me - they found a bug in the handling of client secret basic auth, which they believe has now been fixed. For those who were affected, please report back if you're still experiencing issues, otherwise we'll close this issue.
Just FYI: when i tried to dlownload the client_secrets.json file for an auto-generated oAuth 2.0 client I set up on Google Developers Console there was no client_secret included in the file. But I just manually generated a new oAuth 2.0 client and download it's client_secrets.json file and it has all of the required properties.
So maybe check your auto-generated client JSON files? or this could be just an issue with older oAuth clients. My auto-generated one was from November 2016...
Thanks everyone, this was a provider bug that has now been fixed.
I'm facing this issue at the moment with LinkedIn. Tried to add the client id and secret to the body as suggested here, but no luck.
Any new info on this?
For LinkedIn provider @alexobenauer 's comment solves the issue, I had to change the lib locally to test it. We also had to to pass nil for codeVerifier
when initialising OIDAuthorizationRequest
:
OIDAuthorizationRequest *request = [[OIDAuthorizationRequest alloc]
initWithConfiguration:configuration
clientId:clientId
clientSecret:clientSecret
scope:scope
redirectURL:redirectURL
responseType:OIDResponseTypeCode
state:state
nonce:nil
codeVerifier:nil
codeChallenge:codeChallenge
codeChallengeMethod:OIDOAuthorizationRequestCodeChallengeMethodS256
additionalParameters:nil];
a
I am still experiencing this issue.
A large number of our macOS & iOS users have all of a sudden started seeing this error:
We haven't updated our app, nor changed anything. This is what we're doing:
It's completely random but started happening recently (since last week). 50% of the users aren't having any issues. I've ensure we're using the latest AppAuth code.
Any ideas?