I just got the following result when I tried to do oauth2 to googleapi. Only one thing: I couldn't find what is id_token used for in documentation.
{
"access_token": "xxxx",
"token_type": "Bearer",
"expires_in": 3600,
"id_token": "veryverylongstring",
"refresh_token": "abcdefg"
}
id_token is a JSON Web Token (JWT). If you decode it, you'll see it contains multiple assertions, including the ID of the user. See this answer for more details.
The id_token is used in OpenID Connect protocol, where the user is authenticated as well as authorized. (There's an important distinction
between authentication and authorization.) You will get id_token and access_token.
The id_token value contains the information about the user's authentication. The ID token resembles the concept of an identity card, in a standard JWT format, signed by the OpenID Provider (OIDP). To obtain one, the client needs to send the user to their OIDP with an authentication request.
Features of the ID token:
Asserts the identity of the user, called subject in OpenID (sub).
Specifies the issuing authority (iss).
Is generated for a particular audience, i.e. client (aud).
May contain a nonce (nonce).
May specify when (auth_time) and how, in terms of strength (acr), the user was authenticated.
Has an issue (iat) and expiration time (exp).
May include additional requested details about the subject, such as name and email address.
Is digitally signed, so it can be verified by the intended
recipients. May optionally be encrypted for confidentiality.
The ID token statements, or claims, are packaged in a simple JSON object:
{
"sub" : "alice",
"iss" : "https://openid.c2id.com",
"aud" : "client-12345",
"nonce" : "n-0S6_WzA2Mj",
"auth_time" : 1311280969,
"acr" : "c2id.loa.hisec",
"iat" : 1311280970,
"exp" : 1311281970
}
Related
Received access token from AAD, using below url
https://login.microsoftonline.com/gdfdddddd-87dd-497c-b894-xxxxxx/oauth2/v2.0/token
grant_type :client_credentials
client_id :xxxxx-1ff5-4615-8d71-yyyyyy
client_secret:[7aCw]fdsfsfsfds.AC61Fg:cm33
scope : https://vault.azure.net/.default
Validated the above received token using below code manually & it works fine
IConfigurationManager<OpenIdConnectConfiguration> configurationManager = new ConfigurationManager<OpenIdConnectConfiguration>("https://login.microsoftonline.com/TestDomain310320.onmicrosoft.com/v2.0/.well-known/openid-configuration", new OpenIdConnectConfigurationRetriever());
OpenIdConnectConfiguration openIdConfig = AsyncHelper.RunSync(async () => await configurationManager.GetConfigurationAsync(CancellationToken.None));
TokenValidationParameters validationParameters =
new TokenValidationParameters
{
ValidIssuer = "https://sts.windows.net/a3d2bff3-87dd-497c-b894-f63befdd7496/",
ValidAudiences = new[] { "https://vault.azure.net" },
IssuerSigningKeys = openIdConfig.SigningKeys
};
SecurityToken validatedToken;
JwtSecurityTokenHandler handler = new JwtSecurityTokenHandler();
var user = handler.ValidateToken(token, validationParameters, out validatedToken);
Modified parameter Scope:https://graph.microsoft.com/.default & received AAD token successfully but token validation using above code fails with error message "IDX10511: Signature validation failed. Keys tried: '[PII is hidden]'." Verified AAD app with above mentioned client id is having "user.read/user.read.basicall permissions". Why token validation fails if tokens are received from AAD with Scope:https://graph.microsoft.com/.default
Observation:
Token received with scope : https://vault.azure.net/.default
{
"typ": "JWT",
"alg": "RS256",
"x5t": "YMELHT0gvb0mxoSDoYfomjqfjYU",
"kid": "YMELHT0gvb0mxoSDoYfomjqfjYU"
}
While token received with Scope:https://graph.microsoft.com/.default has extra nonce property to avoid replay attack, is it be the reason for token validation failure?
{
"type": "JWT",
"nonce": "wCXLm9rF5Nma2S7OswU44uAVRpVbM_20WrWJkqbWe6Y",
"alg": "RS256",
"x5t": "YMELHT0gvb0mxoSDoYfomjqfjYU",
"kid": "YMELHT0gvb0mxoSDoYfomjqfjYU"
}
please suggest.
You should not be looking into, or validating tokens that were not issued to your own Apis. The intended receiver, KeyVault and MS Graph will do the necessary validation themselves. You should treat these Access Tokens as an opaque blobs that you stuff into the Authorization header in your calls to these Apis.
An Api owner, Graph or KeyVault can tomorrow can change the claims present in them or even choose to encrypt their tokens and your code will break.
Why are you validating tokens? If you are reading validated tokens of Apis that do not belong to you in your applications as a proof of Authentication, then you are setting yourself up for failure. Also its a security concern as any app in the world which can obtain an Access token for KeyVault or MS graph can pass it your Apis and compromise it.
Here is a discussion for reference - Cannot validate signature. #609
Yes, the error was caused by the nonce field in JWT header.
As far as I know, if we request the access token of graph api, the JWT token will contain the nonce field. And then we can't validate it on our backend(For security reasons, microsoft doesn't allow us to do this operation).
I'm new using JWTs. I have an API that generates a JWT for the clients to be authenticated for further requests. My JWT has a property that returns the user id:
{
jwt: {
exp: "2017-12-12 00:00:00",
data: {
user_id: 491
}
}
}
My question is if the client can decode the JWT generated by the API and add a new property into the data field, like this:
{
jwt: {
exp: "2017-12-12 00:00:00",
data: {
user_id: 491,
status: 1
}
}
}
Or, if I can generate the JWT from the API auth system with the status field set to a default value and then the client could change it.
Thank you.
The client can do that, but it would make the token invalid. When you change the content of the payload, e.g. add another field or change its content, the signature of the token no longer matches. When the API receives a token with invalid signature it should reject the token. Imagine if you had a field called isAdmin and the client could change it from false to true. It would make your authentication pointless; the client doesn't decide whether it's admin or not, the backend does.
When the token's payload changes the signature has to be remade. In order to sign the token, the client has to know the secret key (for H256). But the client shouldn't know the secret key.
So the answer is no, the client can't change the token.
You can read more about that here.
In other words, you want to tamper with your JWT token and you cannot do it without invalidating the token.
The signature is calculated over the header and over the payload. The token issuer (the server) checks the signature to verify that the content has not been changed along the way.
In the latest Version of JWT Auth
$token = JWTAuth::claims(['account_id' => $account->id])->fromUser($user);
to data from token :
$payload = JWTAuth::getPayload();
$accountId = $payload->get('account_id');
in the preview version of JWT auth
$token = JWTAuth::fromUser($user, ['account_id' => $account->id]);
to data from token :
$payload = JWTAuth::getPayload(JWTAuth::getToken());
I am using the Passport AAD project with the bearer strategy to protect my endpoints. After I receive tokens with the OIDC strategy when logging in, I can't seem to get the bearer strategy to validate the signature of the access token. I get:
authentication failed due to: invalid signature
I have no problems validating the id_token, but I would prefer not to use this for our client app if the id_token can't be refreshed with AAD. Also, when using jwt.io to test the validation with the published public keys, I see the same issue (can validate the id_token, but not the access_token).
Am I missing a step when grabbing the access token, or is there a gap in my understanding of how access tokens are validated?
Update with more details
I am requesting an access token from my tenant:
identityMetadata: https://login.microsoftonline.com/your_tenant_name.onmicrosoft.com/.well-known/openid-configuration,
responseType: 'id_token code'
Using the OIDCStrategy in the AAD Passport project.
const callbackOIDC = (iss, sub, profile, accessToken, refreshToken, params, done) => {
return done(null,{
profile,
accessToken,
refreshToken
});
};
passport.use(new OIDCStrategy(config.creds, callbackOIDC));
Then I run authenticate, shown below:
auth.adCallback = function (req, res, next) {
passport.authenticate('azuread-openidconnect', {
response: res,
resourceURL: 'https://graph.microsoft.com',
session: false
}, function (err, user, info) {
console.log(user.access_token);
})(req, res, next);
};
I think I may have been asking for a graph access token above by specifying the resource URL. If I remove that resource URL, I still get an access token, but the bearer strategy throws an invalid token error (instead of an invalid signature error). Is there a different resource URL I should be setting to match with my tenant and get the access token I'm looking for?
What access tokens are you requesting? If the access token is meant to be used against the Microsoft Graph, for example, it is the Graph's task to validate them- not your app's.
Can you expand on the exact scenario you are trying to implement, and at what point you need to refresh id_tokens?
I am developing software for some YouTube channels not owned by myself.
To retrieve insight data, I need to be authenticated. How to achieve that?
Try OAuth 2.0 for installed application: http://code.google.com/apis/youtube/2.0/developers_guide_protocol.html#OAuth2_Installed_Applications_Flow
First, register the API to get a client_id.
Then, ask the partner to log into their google account, type the following URL, change the client_id with yours. redirect_uri should be set to "urn:ietf:wg:oauth:2.0:oob".
https://accounts.google.com/o/oauth2/auth?client_id=1084945748469-eg34imk572gdhu83gj5p0an9fut6urp5.apps.googleusercontent.com&redirect_uri=urn:ietf:wg:oauth:2.0:oob&scope=https://gdata.youtube.com&response_type=code&access_type=offline
Then they authorize you application and get an authorization code.
Then open a terminal and type (change your code, client_id, and client_secret):
curl https://accounts.google.com/o/oauth2/token -d "code=4/ux5gNj-_mIu4DOD_gNZdjX9EtOFf&client_id=1084945748469-eg34imk572gdhu83gj5p0an9fut6urp5.apps.googleusercontent.com&client_secret=hDBmMRhz7eJRsM9Z2q1oFBSe&redirect_uri=urn:ietf:wg:oauth:2.0:oob&grant_type=authorization_code"
You will get response like:
{
"access_token" : "ya29.AHES6ZTtm7SuokEB-RGtbBty9IIlNiP9-eNMMQKtXdMP3sfjL1Fc",
"token_type" : "Bearer",
"expires_in" : 3600,
"refresh_token" : "1/HKSmLFXzqP0leUihZp2xUt3-5wkU7Gmu2Os_eBnzw74"
}
Remember the refresh_token, and every time you run your application, you need to get a new access_token with the refresh_token.
Does anyone have sample code or clear instructions on how to use libEtPan to connect to a GMail account using OAuth? I couldn't find anything.
Details for OAuth in GMail are here: http://code.google.com/apis/gmail/oauth/
libetpan has some documentation in its header files, for IMAP it's in https://github.com/dinhviethoa/libetpan/blob/master/src/low-level/imap/mailimap_oauth2.h
/*
mailimap_oauth2_authenticate()
Authenticates the client using using an oauth2 token.
To gather a deeper understanding of the OAuth2 aunthentication
process refer to: https://developers.google.com/gmail/xoauth2_protocol
For a quick start you may follow this brief set of steps:
1. Set up a profile for your app in the Google
API Console: https://code.google.com/apis/console
2. With your recently obtained client_id and secret
load the following URL (everything goes ina single line):
https://accounts.google.com/o/oauth2/auth?client_id=[YOUR_CLIENT_ID]&
redirect_uri=urn%3Aietf%3Awg%3Aoauth%3A2.0%3Aoob&
response_type=code&scope=https%3A%2F%2Fmail.google.com%2F%20email&
&access_type=offline
3. The user most follow instructions to authorize application access
to Gmail.
4. After the user hits the "Accept" button it will be redirected to another
page where the access token will be issued.
5. Now from the app we need and authorization token, to get one we issue a POST request
the following URL: https://accounts.google.com/o/oauth2/token using these parameters:
client_id: This is the client id we got from step 1
client_secret: Client secret as we got it from step 1
code: This is the code we received in step 4
redirect_uri: This is a redirect URI where the access token will be sent, for non
web applications this is usually urn:ietf:wg:oauth:2.0:oob (as we got from step 1)
grant_type: Always use the authorization_code parameter to retrieve an access and refresh tokens
6. After step 5 completes we receive a JSON object similar to:
{
"access_token":"1/fFAGRNJru1FTz70BzhT3Zg",
"refresh_token":"1/fFAGRNJrufoiWEGIWEFJFJF",
"expires_in":3920,
"token_type":"Bearer"
}
The above output gives us the access_token, now we need to also retrieve the user's e-mail,
to do that we need to perform an HTTP GET request to Google's UserInfo API using this URL:
https://www.googleapis.com/oauth2/v1/userinfo?access_token=[YOUR_ACCESS_TOKEN]
this will return the following JSON output:
{
"id": "00000000000002222220000000",
"email": "email#example.com",
"verified_email": true
}
#param session IMAP session
#param auth_user Authentication user (tipically an e-mail address, depends on server)
#param access_token OAuth2 access token
#return the return code is one of MAILIMAP_ERROR_XXX or
MAILIMAP_NO_ERROR codes
*/
LIBETPAN_EXPORT
int mailimap_oauth2_authenticate(mailimap * session, const char * auth_user,
const char * access_token);
LIBETPAN_EXPORT
int mailimap_has_xoauth2(mailimap * session);
I haven't tried it out myself yet, but when I get around to implement it I'll post a link of the implementation.
Update March 2021
I finally got around to implement support for Google OAuth 2.0 in my email client nmail now. The commit can be viewed here but essentially I ended up doing steps 2-6 above in a separate external script, as libetpan does not do the token generation/refresh for us. The token handling is fairly straight-forward - see oauth2nmail.py for example.