Microsoft Graph - CompactToken parsing failed with error code: 8004920A - c++

I am requesting access token from Microsoft Graph using this procedure:
I request access to the following scopes:
User.Read.All openid profile email offline_access https://outlook.office.com/IMAP.AccessAsUser.All https://outlook.office.com/POP.AccessAsUser.All https://outlook.office.com/SMTP.Send
After the consent screen in web browser, the redirection occurs and the codes are sent to temporary localhost web server running on user's PC.
The code received is exchanged for access_token and refresh_token
When I try to query Microsoft Graph for user's profile I query:
GET https://graph.microsoft.com/v1.0/me
Header of the GET request contains:
Authorization: Bearer token-here-all-in-one-line
But I get the resulting JSON:
"InvalidAuthenticationToken"
"CompactToken parsing failed with error code: 8004920A"
I would normally assume the token is not correct, but I tested the same token from C++ app and a small PHP app, and I always test the same error. To be sure that it is not the wrong token, I deliberately modify it to a wrong token and then I get:
"CompactToken parsing failed with error code: 80049217"
After googling - 8004920A means "token rejected" (the error I have problem with) and 80049217 means "malformed token" so that is consistent with me deliberately inserting false data as token.
So I would assume that the token is correct but Microsoft Graph rejects it to query user profile information which is consented and approved.
I have tested the token on IMAP and SMTP access and there it works - mails are sent and received, so the access_token is definitely good.
Any ideas why Microsoft Graph rejects my attempt to query user profile?
Do I need to enable something when registering application in AzureAD portal?
I am doing this from C++ or from PHP so I don't think the code is of relevance here.

Not sure if this is the case, but it may be. You cannot use the same token for graph access and another API acccess (such as Outlook REST api, in your case). Meaning, you cannot mix scopes from different namespaces. Not sure why ("by design"?), you just can't. You need two separate tokens.
I faced similar issue with SharePoint REST api access (so may not be 100% sure it is also true for Outlook as well, but probably it is). I used a relatively easy way out - exchanging the token requested for openid profile email offline_access for token for https://outlook.office.com/... on my server (using the on_behalf_of flow).
If you don't really need the graph scope User.Read.All you could also try simply removing that one from your first authorization call that obtains the token.

As #Nikolay has stated, the tokens for Graph and Outlook can't be mixed. And Microsoft has designed it poorly so that IMAP.AccessAsUser.All for example can't be used for IMAP access - the access_token simply won't work unless the https://outlook.office.com/ prefix is added.
But - I found another way, which works for just reading the user's profile and email address which is by decoding the id_token. As Microsoft documentation states - openid profile and email scopes will work with both Graph and Outlook. profile token can be used to extract the information about user's profile.
As explained on:
https://learn.microsoft.com/en-us/azure/active-directory/develop/id-tokens
id_token contains information such as email address, name etc.
A sample ID token from their page is:
eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6IjFMVE16YWtpaGlSbGFfOHoyQkVKVlhlV01xbyJ9.eyJ2ZXIiOiIyLjAiLCJpc3MiOiJodHRwczovL2xvZ2luLm1pY3Jvc29mdG9ubGluZS5jb20vOTEyMjA0MGQtNmM2Ny00YzViLWIxMTItMzZhMzA0YjY2ZGFkL3YyLjAiLCJzdWIiOiJBQUFBQUFBQUFBQUFBQUFBQUFBQUFJa3pxRlZyU2FTYUZIeTc4MmJidGFRIiwiYXVkIjoiNmNiMDQwMTgtYTNmNS00NmE3LWI5OTUtOTQwYzc4ZjVhZWYzIiwiZXhwIjoxNTM2MzYxNDExLCJpYXQiOjE1MzYyNzQ3MTEsIm5iZiI6MTUzNjI3NDcxMSwibmFtZSI6IkFiZSBMaW5jb2xuIiwicHJlZmVycmVkX3VzZXJuYW1lIjoiQWJlTGlAbWljcm9zb2Z0LmNvbSIsIm9pZCI6IjAwMDAwMDAwLTAwMDAtMDAwMC02NmYzLTMzMzJlY2E3ZWE4MSIsInRpZCI6IjkxMjIwNDBkLTZjNjctNGM1Yi1iMTEyLTM2YTMwNGI2NmRhZCIsIm5vbmNlIjoiMTIzNTIzIiwiYWlvIjoiRGYyVVZYTDFpeCFsTUNXTVNPSkJjRmF0emNHZnZGR2hqS3Y4cTVnMHg3MzJkUjVNQjVCaXN2R1FPN1lXQnlqZDhpUURMcSFlR2JJRGFreXA1bW5PcmNkcUhlWVNubHRlcFFtUnA2QUlaOGpZIn0.1AFWW-Ck5nROwSlltm7GzZvDwUkqvhSQpm55TQsmVo9Y59cLhRXpvB8n-55HCr9Z6G_31_UbeUkoz612I2j_Sm9FFShSDDjoaLQr54CreGIJvjtmS3EkK9a7SJBbcpL1MpUtlfygow39tFjY7EVNW9plWUvRrTgVk7lYLprvfzw-CIqw3gHC-T7IK_m_xkr08INERBtaecwhTeN4chPC4W3jdmw_lIxzC48YoQ0dB1L9-ImX98Egypfrlbm0IBL5spFzL6JDZIRRJOu8vecJvj1mq-IUhGt0MacxX8jdxYLP-KUu2d9MbNKpCKJuZ7p8gwTL5B7NlUdh_dmSviPWrw
The token consists of 3 parts - header, payload and the signature. They are separated by a dot. That's a standard JWT (JSON Web Token) See details at - https://en.wikipedia.org/wiki/JSON_Web_Token
After separating them and then base64 decoding each (the signature doesn't give anything useful after decoding) the result is:
1) The header
{
"typ": "JWT",
"alg": "RS256",
"kid": "1LTMzakihiRla_8z2BEJVXeWMqo"
}
2) The payload
Payload which contains the user info. Additional information can be extracted by adding Optional claims when registering app in Azure AD - (Token configuration in the menu on the left).
{
"ver": "2.0",
"iss": "https://login.microsoftonline.com/9122040d-6c67-4c5b-b112-36a304b66dad/v2.0",
"sub": "AAAAAAAAAAAAAAAAAAAAAIkzqFVrSaSaFHy782bbtaQ",
"aud": "6cb04018-a3f5-46a7-b995-940c78f5aef3",
"exp": 1536361411,
"iat": 1536274711,
"nbf": 1536274711,
"name": "Abe Lincoln",
"preferred_username": "AbeLi#microsoft.com",
"oid": "00000000-0000-0000-66f3-3332eca7ea81",
"tid": "9122040d-6c67-4c5b-b112-36a304b66dad",
"nonce": "123523",
"aio": "Df2UVXL1ix!lMCWMSOJBcFatzcGfvFGhjKv8q5g0x732dR5MB5BisvGQO7YWByjd8iQDLq!eGbIDakyp5mnOrcdqHeYSnltepQmRp6AIZ8jY"
}
3) The signature
For verification purposes only.
1AFWW-Ck5nROwSlltm7GzZvDwUkqvhSQpm55TQsmVo9Y59cLhRXpvB8n-55HCr9Z6G_31_UbeUkoz612I2j_Sm9FFShSDDjoaLQr54CreGIJvjtmS3EkK9a7SJBbcpL1MpUtlfygow39tFjY7EVNW9plWUvRrTgVk7lYLprvfzw-CIqw3gHC-T7IK_m_xkr08INERBtaecwhTeN4chPC4W3jdmw_lIxzC48YoQ0dB1L9-ImX98Egypfrlbm0IBL5spFzL6JDZIRRJOu8vecJvj1mq-IUhGt0MacxX8jdxYLP-KUu2d9MbNKpCKJuZ7p8gwTL5B7NlUdh_dmSviPWrw

Related

Should resource_owner/User-id be included in the OAuth 2.0 Access Token response?

This is a problem we are confronted with today. I looked online as much as I can before deciding to ask the question here.
The question is, when a user makes a "Access Token Request" with a username/password, should the Access Token response contain "user-id" field?
The OAuth 2.0 spec says there can be an extra field (search for "example_parameter" in the spec) as part of the access token response. Can this extra field be user-id?
However, Many of the companies like facebook/google/twitter does not provide user-id as part of the access token response. User-id is provided as part of the validate token response.
What are the reasons for not providing user-id as part of the Access Token response? Why do we have to make another call (an extra round trip) if we need a user-id? What are the consequences of providing user-id as part of the Access Token response?
Most applications don't want to leak their user-ids to the UI layer. It is generally considered bad practice. If you send the userid to the UI layer, the UI will have the ability to request information about that UserId, and get information about it back...
This presents a security issue, as the client can generally modify these calls to get information about other UserIDs... If you are going to authenticate each call each time to validate that the token is bound to that user id, then it likely is a waste to have the client pass the userid itself, you are already doing the lookup, so you might as well keep the data internal to the service.
This also sets you up nicely to change your concept of a UserId in the future, maybe changing it to be group id, or an email address instead of the database userid...
Oauth2.0 is an authorisation framework and doesn't deal with user authentication.
The question is, when a user makes a "Access Token Request" with a
username/password, should the Access Token response contain "user-id"
field? In this context the resource
It's really a client requesting an access token and in many cases a client doesn't want to know about the id of the resource owner it just wants a token to allow it it call an endpoint on the resource server. The resource server can identity the user from the contents of the access token.
OpenID Connect can be used to extend OAuth2.0 to include an ID token. This gives basic user info in a standard format without the need to call a further endpoint.
An access token is a normally a bearer token that allows you to call an API. In OpenID Connect, you use the access token to call an api called the user_info endpoint, which returns a JSON object that contains information about the person, like first name, last name, etc. If you are looking for a free open source central authentication server that supports OAuth2, you should look at the Gluu Server http://gluu.org

Verify oauth.io facebook access token

I am using oauth.io to handle authentication in an Android app. I login using the service and then pass the access token to the server. As part of the server-side verification, I make a call to https://graph.facebook.com/debug_token?input_token={user access token}&access_token={app token}. I was receiving a response with the error message "(#100) The App_id in the input_token did not match the Viewing App".
I took this to mean that the app that generated the access token was not the same as the app that owns the app token I was sending in the request. Upon further inspection, I noticed that when I debugged the token with Facebook's tool (https://developers.facebook.com/tools/debug/accesstoken) I was seeing a different app id that belonged to oauth.io itself instead of my app. Since the app token is based on the app id and app secret, it obviously would not be correct if it was expecting oauth.io's app token.
Is there any way to continue using the debug_token endpoint through Facebook with a token generated by oauth.io?
Sorry this is a bit late - but it may still help you :) I had the same issue. In my perl code, I just did:
use LWP::Simple;
my $check_session_first = LWP::Simple::get("https://graph.facebook.com/me?access_token=$in->{token}");
if (!$check_session_first) {
print $IN->header;
print Links::SiteHTML::display('error', { error => qq|Sorry, we couldn't log you in. |});
return;
}
Basically, if $check_session_first is empty, then it means the session isn't valid. If its valid, it'll return a JSON object (which in my case, I process using the "JSON" perl module)

Application Token is Different

On this page:
http://developers.facebook.com/docs/opengraph/using-app-tokens/
It describes how to get the app access token, yet the token it returns is different than the one in the open Graph "Get Code" example. The latter is the only one that works. How can I get the second access token using the API? When I try to use the first example, I basically get something back that looks like "application ID|secret key" which is different than the real access token.
as documentation states, you will get
access_token=YOUR_APP_ACCESS_TOKEN
string back from the API call. Even though it LOOKS like "application ID|secret key HASH" - it is a valid access token you can use to publish to user's wall. You can verify it's a proper access token using Debug toll from FB: https://developers.facebook.com/tools/debug - just paste the token there.
The reason it might not work for you is because you are trying to publish something to the user's wall who did not authorize your app. Look here: https://developers.facebook.com/docs/reference/javascript/ - for example of how to use your app ID to make user authorize the app. You need to request publish_stream permission for your app from user in order to be able to publish as the app to the user's wall.
And going back to the documentation:
Note that the app access token is for publishing purposes permitted by
the publish_actions and publish_stream permissions. You will be unable
to retrieve information about the status update post with the given ID
using the app access token. Instead, you should use a user access
token for such purposes.
hope that helps.

Facebook Graphi API does not list page accounts in offline mode

My offline Facebook application is trying to retrieve the accounts associated with a specific user id who has previously authorized the application:
https://graph.facebook.com/(userid)/accounts?access_token=(token)
Even though I am passing a valid access token, Facebook returns:
OAuthException: An access token is required to request this resource.
I verified that my access token is correct by querying the likes connection with the same userid and access token:
https://graph.facebook.com/(userid)/likes?access_token=(token)
For this second statement, Facebook returns the expected result.
My application has manage_pages and offline_access permissions. The access token I am using is the access token Facebook returned when the user authorized the application. I don't understand why it works for the likes connection but not for the accounts connection.
Facebook provides different access tokens, some are shorter and some are longer. Without realizing the difference, I had used the shorter ones, created as type='client_cred'. These work fine for retrieving friends lists, lists of fan pages, publishing to stream etc. but apparently they do not work for getting accounts information.
Here is an example of both types of access tokens. Apparently the first one lacks session information (which is the middle part of the second access token).
116122545078207|EyWJJYqrdgQgV1bfueck320z7MM.
116122545078207|2.1vGZASUSFMHeMVgQ_9P60Q__.3600.1272535200-500880518|EyWJJYqrdgQgV1bfueck320z7MM.
If your access token is wrong facebook returns this:
{
"error": {
"type": "OAuthException",
"message": "Error validating access token."
}
}
It seems that the token is not passed to the graph api. Depending on which SDK you use to pass the token, there are different errors that can occur. The PHP SDK for example ignores the token you pass and tries to get the token from the session cookie, which causes errors. Could you clarify how are you making the graph api calls?
I have verified that with a valid token you can get the accounts data. Have you tried pasting this into your browser https://graph.facebook.com/(userid)/accounts?access_token=(token)?

How can I verify a Google authentication API access token?

How can I verify a Google authentication access token?
I need to somehow query Google and ask: Is [given access token] valid for the [example#example.com] Google account?
Short version
It's clear how an access token supplied through the Google Authentication Api :: OAuth Authentication for Web Applications can be used to then request data from a range of Google services. It is not clear how to check if a given access token is valid for a given Google account. I'd like to know how.
Long version
I'm developing an API that uses token-based authentication. A token will be returned upon provision of a valid username+password or upon provision of a third-party token from any one of N verifiable services.
One of the third-party services will be Google, allowing a user to authenticate against my service using their Google account. This will later be extended to include Yahoo accounts, trusted OpenID providers and so on.
Schematic example of Google-based access:
The 'API' entity is under my full control. The 'public interface' entity is any web- or desktop-based app. Some public interfaces are under my control, others will not be and others still I may never even know about.
Therefore I cannot trust the token supplied to the API in step 3. This will be supplied along with the corresponding Google account email address.
I need to somehow query Google and ask: Is this access token valid for example#example.com?
In this case, example#example.com is the Google account unique identifier - the email address someone uses to log in to their Google account. This cannot be assumed to be a Gmail address - someone can have a Google account without having a Gmail account.
The Google documentation clearly states how, with an access token, data can be retrieved from a number of Google services. Nothing seems to state how you can check if a given access token is valid in the first place.
Update
The token is valid for N Google services. I can't try a token against a Google service as means of verifying it as I won't know which subset of all Google's services a given user actually uses.
Furthermore, I'll never be using the Google authentication access token to access any Google services, merely as a means of verifying a supposed Google user actually is who they say they are. If there is another way of doing this I'm happy to try.
For user check, just post
get the access token as accessToken and post it and get the response
https://www.googleapis.com/oauth2/v1/tokeninfo?access_token=accessToken
you can try in address bar in browsers too, use httppost and response in java also
response will be like
{
"issued_to": "xxxxxxxxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.apps.googleusercontent.com",
"audience": "xxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxx.apps.googleusercontent.com",
"user_id": "xxxxxxxxxxxxxxxxxxxxxxx",
"scope": "https://www.googleapis.com/auth/userinfo.profile https://gdata.youtube.com",
"expires_in": 3340,
"access_type": "offline"
}
The scope is the given permission of the accessToken. you can check the scope ids in this link
Update:
New API
post as below
https://oauth2.googleapis.com/tokeninfo?id_token=XYZ123
Response will be as
{
// These six fields are included in all Google ID Tokens.
"iss": "https://accounts.google.com",
"sub": "110169484474386276334",
"azp": "1008719970978-hb24n2dstb40o45d4feuo2ukqmcc6381.apps.googleusercontent.com",
"aud": "1008719970978-hb24n2dstb40o45d4feuo2ukqmcc6381.apps.googleusercontent.com",
"iat": "1433978353",
"exp": "1433981953",
// These seven fields are only included when the user has granted the "profile" and
// "email" OAuth scopes to the application.
"email": "testuser#gmail.com",
"email_verified": "true",
"name" : "Test User",
"picture": "https://lh4.googleusercontent.com/-kYgzyAWpZzJ/ABCDEFGHI/AAAJKLMNOP/tIXL9Ir44LE/s99-c/photo.jpg",
"given_name": "Test",
"family_name": "User",
"locale": "en"
}
For more info, https://developers.google.com/identity/sign-in/android/backend-auth
Ok, most answers are valid but not quite right. The idea of JWT is that you can validate the token without the need to contact the issuer everytime. You must check the id and verify the signature of the token with the known public key of the certificate google used to sign the token.
See the next post why and how to do this.
http://ncona.com/2015/02/consuming-a-google-id-token-from-a-server/
you can verify a Google authentication access token by using this endpoint:
https://www.googleapis.com/oauth2/v3/tokeninfo?access_token=<access_token>
This is Google V3 OAuth AccessToken validating endpoint, you can refer from google document below: (In OAUTH 2.0 ENDPOINTS Tab)
https://developers.google.com/identity/protocols/OAuth2UserAgent#validate-access-token
function authenticate_google_OAuthtoken($user_id)
{
$access_token = google_get_user_token($user_id); // get existing token from DB
$redirecturl = $Google_Permissions->redirecturl;
$client_id = $Google_Permissions->client_id;
$client_secret = $Google_Permissions->client_secret;
$redirect_uri = $Google_Permissions->redirect_uri;
$max_results = $Google_Permissions->max_results;
$url = 'https://www.googleapis.com/oauth2/v1/tokeninfo?access_token='.$access_token;
$response_contacts = curl_get_responce_contents($url);
$response = (json_decode($response_contacts));
if(isset($response->issued_to))
{
return true;
}
else if(isset($response->error))
{
return false;
}
}
Use the below endpoint to get user info such as name, email, photo etc.
https://www.googleapis.com/oauth2/v3/userinfo?access_token=<access token>
Use the below endpoint to get token info, such as expiry time, token scope etc.
https://www.googleapis.com/oauth2/v3/tokeninfo?access_token=<access token>
Google oauth code flow response in addition to access_token also returns id_token that contains useful for validation info in encrypted form.
One thing that makes ID tokens useful is that fact that you can pass
them around different components of your app. These components can use
an ID token as a lightweight authentication mechanism authenticating
the app and the user. But before you can use the information in the ID
token or rely on it as an assertion that the user has authenticated,
you must validate it.
Validation of an ID token requires several steps:
Verify that the ID token is a JWT which is properly signed with an appropriate Google public key.
Verify that the value of aud in the ID token is equal to your app’s client ID.
Verify that the value of iss in the ID token is equal to accounts.google.com or https://accounts.google.com.
Verify that the expiry time (exp) of the ID token has not passed.
If you passed a hd parameter in the request, verify that the ID token has a hd claim that matches your Google Apps hosted domain.
https://developers.google.com/identity/protocols/OpenIDConnect#validatinganidtoken link has code samples for validation of ID tokens.
See also https://security.stackexchange.com/questions/37818/why-use-openid-connect-instead-of-plain-oauth.
As per Google's documentation, you should use Google's AP Client Library that makes this (token verification, claim extraction etc.) much easier than writing your own custom code.
From a performance perspective, the token should be parsed locally without making a call to Google again. Off-course Google's public key is needed and retrieval of that key is done using a caching strategy, implemented in the Google's client library from #1 above.
FYI only. Google also uses a JWT token. See image below for reference.
Here's an example using Guzzle:
/**
* #param string $accessToken JSON-encoded access token as returned by \Google_Client->getAccessToken() or raw access token
* #return array|false False if token is invalid or array in the form
*
* array (
* 'issued_to' => 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.apps.googleusercontent.com',
* 'audience' => 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.apps.googleusercontent.com',
* 'scope' => 'https://www.googleapis.com/auth/calendar',
* 'expires_in' => 3350,
* 'access_type' => 'offline',
* )
*/
public static function tokenInfo($accessToken) {
if(!strlen($accessToken)) {
return false;
}
if($accessToken[0] === '{') {
$accessToken = json_decode($accessToken)->access_token;
}
$guzzle = new \GuzzleHttp\Client();
try {
$resp = $guzzle->get('https://www.googleapis.com/oauth2/v1/tokeninfo', [
'query' => ['access_token' => $accessToken],
]);
} catch(ClientException $ex) {
return false;
}
return $resp->json();
}
I need to somehow query Google and ask: Is this access token valid for example#example.com?
No. All you need is request standard login with Federated Login for Google Account Users from your API domain. And only after that you could compare "persistent user ID" with one you have from 'public interface'.
The value of realm is used on the Google Federated Login page to identify the requesting site to the user. It is also used to determine the value of the persistent user ID returned by Google.
So you need be from same domain as 'public interface'.
And do not forget that user needs to be sure that your API could be trusted ;) So Google will ask user if it allows you to check for his identity.
Try making an OAuth-authenticated request using your token to https://www.google.com/accounts/AuthSubTokenInfo. This is only documented to work for AuthSub, but it works for OAuth too. It won't tell you which user the token is for, but it will tell you which services it's valid for, and the request will fail if the token is invalid or has been revoked.
An arbitrary OAuth access token can't be used for authentication, because the meaning of the token is outside of the OAuth Core spec. It could be intended for a single use or narrow expiration window, or it could provide access which the user doesn't want to give. It's also opaque, and the OAuth consumer which obtained it might never have seen any type of user identifier.
An OAuth service provider and one or more consumers could easily use OAuth to provide a verifiable authentication token, and there are proposals and ideas to do this out there, but an arbitrary service provider speaking only OAuth Core can't provide this without other co-ordination with a consumer. The Google-specific AuthSubTokenInfo REST method, along with the user's identifier, is close, but it isn't suitable, either, since it could invalidate the token, or the token could be expired.
If your Google ID is an OpenId identifier, and your 'public interface' is either a web app or can call up the user's browser, then you should probably use Google's OpenID OP.
OpenID consists of just sending the user to the OP and getting a signed assertion back. The interaction is solely for the benefit of the RP. There is no long-lived token or other user-specific handle which could be used to indicate that a RP has successfully authenticated a user with an OP.
One way to verify a previous authentication against an OpenID identifier is to just perform authentication again, assuming the same user-agent is being used. The OP should be able to return a positive assertion without user interaction (by verifying a cookie or client cert, for example). The OP is free to require another user interaction, and probably will if the authentication request is coming from another domain (my OP gives me the option to re-authenticate this particular RP without interacting in the future). And in Google's case, the UI that the user went through to get the OAuth token might not use the same session identifier, so the user will have to re-authenticate. But in any case, you'll be able to assert the identity.
Check below URL. It works well. Its official document from Google itself.
Using one of the Google API Client Libraries (e.g. Java, Node.js, PHP, Python) is the recommended way to validate Google ID tokens.
https://developers.google.com/identity/sign-in/android/backend-auth#using-a-google-api-client-library