I understand a token received via...
https://accounts.google.com/o/oauth2/auth
...should be validated before use to prevent the confused deputy problem with a call similar to the following:
https://www.googleapis.com/oauth2/v1/tokeninfo?access_token=1/fFBGRNJru1FQd44AzqT3Zg
...as specified by for instance Google here: Validating the token
However if the token comes from the gapi.auth api, ie:
gapi.auth.authorize({ "client_id": CONST.CLIENT_ID, "scope": OAuthScopes, "immediate": true, "include_granted_scopes": true }, handleAuthResult);
function handleAuthResult(authResult) {
if (authResult && !authResult.error) {
theAccessToken = authResult.access_token;
}
}
...is the validation step already taken care of? I cannot find any Google documentation that makes this clear, and as a security risk, it would be good to hear from a reliable source.
Related
I am using Oauth2+JWT+Spring security in one of my project. When i hit /outh/token using username/password i am receiving access token in the response with other details like
{
"access_token": <token>,
"token_type": <type>,
"refresh_token": <refresh-token>,
"expires_in":<secs>,
"scope": <scope>,
"jti": <value>
}
Is it possible to customize this response like
{
data: {
"access_token": <token>,
"token_type": <type>,
"refresh_token": <refresh-token>,
"expires_in":<secs>,
"scope": <scope>,
"jti": <value>
},
details:{
//extra information
}
}
I'm confused, don't know how to ask more clearly: "what is the additional data you want to send?". Just give an explicit sample.
I'll answer guessing that this data is related to the authorized entity (the user when answering within authorization-code flow and the client within client-credentials flow): non standard data should be set as private-claims, inside the JWT itself and on token introspection endpoint.
How to add such private claims depends on your authorization-server. For spring-security one, this is done with an OAuth2TokenCustomizer. For Keycloak, you have to provide a "mapper", etc.
The client which received a payload like the one you show, will only send the access-token when issuing requests to resource-server(s). It is important that this token holds all of the data needed for resources access decisions. Some claims are specified by OAuth2, OpenID defines some more standard claims, and you are free to put whatever additional data in private claims (within the limits of the maximum token size).
Also, if your client needs to read claims, it should use ID token, not access-token (request openid scope when initiating OAuth2 flow). Access-token should be interpreted by resource-server only.
I have a browser based twilio phone app that works well, but for better security we are integrating access tokens now. But we can't find ANY documentation on grants anywhere. We are constructing everything ourselves in our backend, so we are specifically looking for the variables we need to put in our JSON for that, for receiving calls and sending calls.
I have asked Twilio, but it's sunday. When they return a response, if that comes first, and if it works, I'll put it here to help others who might be looking for this as we are.
ie. here is the JSON payload:
{"sub":"AC*****","nbf":1578251940,"iss":"SK*****","exp":1578338340,"iat":1578252060,"grants":{"identity":"ID_whatever","voice":{"service_sid":"AP*****"}},"jti":"SK*****"}
Any help is appreciated.
Twilio have responded with a working payload template, here it is in case anyone else needs it.
{
// API key SID concatenated with current timestamp
"jti": "SK...-1578329486",
// API key SID
"iss": "SK...",
// account SID
"sub": "AC...",
// expiration timesetamp
"exp": 1578333086,
"grants": {
// Client name
"identity": "alice",
"voice": {
"incoming": {
// if incoming connections are allowed
"allow": true
},
"outgoing": {
// if outgoing connections are allowed, the application SID
"application_sid": "AP..."
}
}
}
I'm using Okta for identity management. As the client in authorization flow, I send an authorize request to Okta. This works successfully, and I get a JWT payload. I want to verify the JWT signature, so I make another call to Okta in order to fetch the keys. However, the key ids (kids) do not match and verification fails.
Initial authorize request:
https://{{site}}.okta.com/oauth2/v1/authorize
?scope=openid
&response_type=id_token
&client_id={{client_id}}
&redirect_uri={{redirect_url}}
&nonce=4euiv0v52at3la15e7qlu1mt43
&state=7c92bqulrmdk2jk0ro9rd3mf5j
Response is a 403, redirecting me to:
{{redirect_url}}/id_token={{id_token}}
The header of the id_token is decoded into:
{
"alg": "RS256",
"kid": "2YKtkekCjCRWN0YqGsjUrNwIQaxGg5ahfHW0_fK8t64"
}
So far so good. I know that the authorization has succeeded. Time to validate the JWT.
However, when this is followed up with:
https://{{site}}.okta.com/oauth2/v1/keys
Or
https://{{site}}.okta.com/oauth2/v1/keys?clientId={{client_id}}
(they both return the same response), I get back this:
{
"keys": [
{
"alg": "RS256",
"e": "AQAB",
"n": "gv1rI9A7mrOoViJZTzUfiZl7YdEzLEofvRoVbXCgeW7aOmoKcAkWGHvqNRGoFgi8auV5b_TSgTXKq_TV1fz643hpAtba3V0Uw2lXchTbqXpmVRYXI1t4FIwRMXLe4Q-kcvp9la21e3D1lszjdPbFNX5GLAhrCW0Thu2HYbTLg6TbDTMaiQCMo15hek0JgZqRGzCkt9kINnwPVLXV_bkSh_fHWo_6G1L0MKYYQcgE6zvPlULLek98-yZ6Nlg6nJUY9nHn0qjhzqqq-bz_Vin8qi3Bt7SjUKwk7HbaugM84AEgDxYE5JgsaALIl5SgIc3GgFEc69qKWymoD-w1a8f1HQ",
"kid": "SOxFkBSLWefjlZoDI49Hk0nqlYtC28cjhTlVAYEzAxs",
"kty": "RSA",
"use": "sig"
}
]
}
Where the kid does not match what I received in the original response.
Where is my mistake?
You need to create an authorization server and use it as the endpoint, for example:
https://{{site}}.okta.com/oauth2/{authorizationServerId}/v1/authorize
You should also be able to use the default one:
https://{{site}}.okta.com/oauth2/default/v1/authorize
Note that this is different than the route you were using (which does not specify an authorization server):
https://{{site}}.okta.com/oauth2/v1/authorize
You should specify an authorization server in your case (like example 1 and 2 above), for both OAuth 2.0 and OpenID Connect.
The problem was that this account was setup with pinned, not rotating keys. oauth2/v1/keys requires the client id to be passed in as a parameter if you are setup with pinned keys; the correct parameter name is "client_id", not "clientId." This results in the expected output.
So, i've got this response from google upon authentication:
{
"user": {
"id": "116807551237969746774",
"email": "123456#gmail.com",
"verified_email": true,
"name": "John Doe",
"given_name": "John",
"family_name": "Doe",
"picture": "https:\/\/lh3.googleusercontent.com\/-XdUIqdMkCWA\/AAAAAAAAAAI\/AAAAAAAAAAA\/4252ldubv5M\/photo.jpg",
"locale": "en"
},
"credentials": {
"access_token": "ya29.GlsSBIA_hMKZIDE_wqJAJS0vrHD_Wd2HfwRTTvLISv0i1uFICCqz4JdEZcL09mFFlGdt71D9pW80SLShHgyeSOZgnWcL5piL5m0jYo1TMU6o0fDLnqGAWm6BY-Wl",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "1\/az_TmhPRaYG5NDH6L9gBeNo6STOD9EbTt1VkkBmp3IQ",
"id_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6IjBlNmExN2I2YjU4MGIzNTFmMGQ5YmEzMzY2YTU0Y2U1NmViOWIxN2UifQ.eyJhenAiOiIxMDAzMjk3NzQ4MDc1LWsxdml0OGMxMHJ1ZnM4cjZpYmZyYmxlZmJhamFoZmllLmFwcHMuZ29vZ2xldXNlcmNvbnRlbnQuY29tIiwiYXVkIjoiMTAwMzI5Nzc0ODA3NS1rMXZpdDhjMTBydWZzOHI2aWJmcmJsZWZiYWphaGZpZS5hcHBzLmdvb2dsZXVzZXJjb250ZW50LmNvbSIsInN1YiI6IjExNjgwNzU1MTIzNzk2OTc0Njc3NCIsImVtYWlsIjoiNzA0MzA2N0BnbWFpbC5jb20iLCJlbWFpbF84PIXpZmllZCI6dHJ1ZSwiYXRfaGFzaCI6IkdrOHFjMTdCcEVGVGZmWkpKbkh6NGciLCJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJpYXQiOjE0ODk4MTIxMzksImV4cCI6MTQ4OTgxNTczOSwibmFtZSI6IkFudG9uIEFsZWtzYW5kcm92IiwicGljdHVyZSI6Imh0dHBzOi8vbGg0Lmdvb2dsZXVzZXJjb250ZW50LmNvbS8tTEJuMTlWX1NEN3cvQUFBQUFBQUFBQUkvQUFBQUFBQUFBQUEvQUFvbXZWMTRMVFIycUgtOXJ5S2dScjIxd3A1Z1FZRGNmUS9zOTYtYy9waG90by5qcGciLCJnaXZlbl9uYW1lIjoiQW50b24iLCJmYW1pbHlfbmFtZSI6IkFsZWtzYW5kcm92IiwibG9jYWxlIjoiZW4ifQ.BHv5BP3ZsagvunfMzGLwmxkBdtoRocPa_PXdq2lrd4D9BoFGkK06eJVbNNbcPOFdAMba3V5lIIG_L499gIy3TTz_PIHBPi6DMSp6uyfkCwf2n-PspZtTbTRlUm5ZvRdAyPEEyLLkWllKkMsRk-Nwp3vhyOLnExzH7SXiEefU4kaXXCpjsHV3GvZ-yhrmNlicEY3TPLwI-tl_lydXTBXRRiPZBGWjHK75hqvQzUktC2Flimd7JnCLhF0FOS3yFKc5D11WPKMOO4YkIQDbBrKY64vyxQAd-Zb2KfvXZi6Dorq7IJF6sK2GAfI3edSaoMZBMa0-x2V7FuFIBLtTgGRnsw"
}
}
I haven't found documentation on what should i do with credentials part of this response? What should i use for user identification? What should be saved as token on client side (ios/android app) in order to revive the session? What does expires_in: 3600 means and what should i do about it? What does token_type: Bearer means and why do i need it? etc.
Thank you, #pinoyyid for clarifications!
The main thing i was looking for is this:
On server side get access_token property from credentials and verify it, using this url
https://www.googleapis.com/oauth2/v1/tokeninfo?access_token={your access_token}
Do whatever you want with the rest of the provided data.
Personally, i'll prefer to generate own token, save it on client side and use it to revive user's session (to verify his identity). Once token is lost for whatever reason, user just will go through the whole process again.
what should i do with credentials part of this response?
Rejoice, for you have done the hard part.
What should i use for user identification?
Anything you like, or nothing at all. It depends on your app's use case.
What should be saved as token on client side (ios/android app) in order to revive the session?
The Refresh Token. Note that "revive the session" is wrong terminology. In OAuth/REST, there are no sessions.
What does expires_in: 3600 means and what should i do about it?
It is saying that the Access Token will expire in 1 hour (3600 seconds). What you should do is use the Refresh Token to acquire a new Access Token by POSTing it as described https://developers.google.com/identity/protocols/OAuth2WebServer#offline
What does token_type: Bearer means?
It means the Access Token should be placed in an HTTP Authorization header whenever you try to access a Google API. Eg Authorization: "Bearer aaaaaaa" where aaaaaa is the Access Token.
and why do i need it?
To prove to Google that your app has been given permission to access a Google resource (eg. a file in Drive) by the owner of that resource.
Our service has a Trello integration, and we use OAuth to authenticate and authorize users. However, we're seeing all of our calls to Trello fail until the service reauthenticates the user. This started with a call to https://api.trello.com/1/lists to post a card, which received a 401 response. Getting a new token (by effectively reauthenticating) solved the problem, so it's not a permissions issue.
This problem initially sounded like a token expiration issue (since expiration=never is evidently supported), but it hasn't happened in the past and we've been using Trello's API for well over a year. Does anyone happen to know Trello's default OAuth token expiration and whether this has changed recently?
Thanks!
If an expiration is not provided in the request, the default value for the OAuth1.0 flow is 30days.
401s can also be caused by a user revoking a Trello token from their accounts page: https://trello.com/my/account.
Additionally, you can check the expiration date of a token via the 1/tokens route: https://trello.com/1/tokens/{tokenValue}?key={TrelloAPIKey}&token={tokenValue}.
An example response to that route looks like this:
{
"id": "a58541ff795dc3d9a124374b",
"identifier": "My Trello Token",
"idMember": "5859bd30f6582fbf01f4a8fc",
"dateCreated": "2016-12-16T16:45:06.810Z",
"dateExpires": null,
"permissions": [
{
"idModel": "69bdfbf01f58582530f4a8fc",
"modelType": "Member",
"read": true,
"write": true
},
{
"idModel": "*",
"modelType": "Board",
"read": true,
"write": true
},
{
"idModel": "*",
"modelType": "Organization",
"read": true,
"write": true
}
]
}
A Trello access token by default never expires. You can check this here:
https://trello.com/{username}/account
Under the 'Applications' section, you will find details of the API tokens associated with your account.