Google OAuth2 - Correct Usage? - google-authentication

I am developing REST API secured using Google OAuth2 (using java if that matters). The approach is as follows:
UI is authenticating through Google and has: google id + token id,
google id + token id are both sent on each request to API as headers,
REST API uses URL https://www.googleapis.com/oauth2/v3/tokeninfo?id_token=token_id to obtain JSON similar to below (where token_id come from request header):
JSON:
{
"iss": "accounts.google.com",
"iat": "14791197651",
"exp": "14795233651",
"at_hash": "xDLxhM85hTYU0KwU-rhPgg",
"aud": "541950199239-s1fag9iaes0s99g4feipe0ih0l75km1l.apps.googleusercontent.com",
"sub": "197763402127980067798",
"azp": "541950819239-s5fag9iaes9s99g4feipe0ih0l75km1l.apps.googleusercontent.com",
"alg": "RS256",
"kid": "db9e3d7cdd1b4178010f89af11cfd37400061afc"
}
and compares sub value to google id from the request header,
if the check passes and user by google id is in our database, then user is authorized to use the REST API (additional logic might be applied).
Is that correct workflow or additional checks need to be done?
Thanks in advance for your help.

Looking into the Google documentation, if you're going to use the tokeninfo endpoint (which you are), you need just the id_token, and then you must also
check that the aud claim contains one of your app's client IDs
so that you can not only validate the token, but ensure it's actually intended for your client.
Ergo, you can just pull the user's unique Google ID from the sub claim, no need to match it against the one received by the client.

Related

How to restrict a user to THEIR resources using JWT when there is no identity in the Access Token?

We have a REST resource like this:
/customer/{customerId}/bill
We want to use the JWT tokens returned from AWS Cognito to secure access to this resource.
The {customerId} here is not the Cognito user id, it's a domain specific id. We have added this domain specific id to the Cognito user as a custom attribute. It comes in the ID token that Cognito returns like this:
{
"sub": "xxxxxxxx-852f-474d-aa9e-a50fd832bcb8",
"aud": "xxxxxxxxsijed6uf54dh0uhi",
"custom:customerId": "4044",
"event_id": "xxxxxx-fc0c-4ffc-affa-f8987714fb2b",
"token_use": "id",
....
}
If we use this ID Token in Authorization: Bearer <ID Token> we can write code (custom authoriser or in-app code) that ensures the customerId in /customer/{customerId}/bill is equal to the value of custom:customerId in the supplied token, and we have secured our API.
But then we read that you should not use ID tokens to secure APIs . The key point being:
"The audience (the aud claim) of the (ID) token is set to the application's identifier, which means that only this specific application should consume this token."
So it seems we need to send an Access Token to secure the API. With Cognito, there is no way we can add any concept of who the user is into the Access Token. We can't add a custom scope like user:4044 for example.
What folks suggest as an approach here is to call the /userinfo endpoint of Cognito on the server-side with the supplied Access Token to learn who the user is. This would enable us to write code (custom authoriser or in-app code) that calls this endpoint and asserts permission. But it's an endpoint call for every request, which seems crazy.
One thought that crossed our minds was to use the Access Token to secure access to the API itself, but also require the ID token, either as a query parameter or a header to allow us do the fine grained access control. But that too starts to feel wrong.
Surely this is a solved problem? What is the right thing to do here?
Sorry, this question is a year old, so my answer is probably irrelevant. But for future wanderer, I would say that, given the limitations of cognito in allowing custom claims in the access token, a call to the /userinfo route is definitely the best way.
The API GATEWAY lets you cache authorizer response for a given user, so you won't be calling the endpoint on every request. Note that some implementations recommend it as a way to make sure that the token haven't been revoked.

Modify API OAuth Token Expire Time

Acumatica Version: 2019R1
I'm looking to either modify the expiry time on granted OAuth tokens using a Connected Application within Acumatica. Currently, my token is granted using the 'api' and the 'offline_access' scopes to be able to access the API, and to get a refresh token.
I am trying to avoid using any type of session/cookie-based authentication, as my system will be solely interacting with the Acumatica REST API from a complete external source, and cannot store any session/cookie-related data.
My ultimate end goal would allow my application a specific token for absolute concurrent access without the need for refreshing, but a longer expiry time would most likely suffice.
For background, I have looked within all of the help docs, and through each of the Acumatica Developer Training courses, but none of them explicitly state if the OAuth protocol is editable.
I've looked in the OAuth 2.0 Framework documentation at https://www.rfc-editor.org/rfc/rfc6749, but while it shows that it is possible to modify the token expiry time/completely remove the expiry, it has no specific information on how to modify it, since Acumatica implemented the framework.
Here is the x-www-form-urlencoded request body being sent to grant the initial token:
grant_type: <password>
client_id: <applicationID>#<company>
client_secret: <secret>
username: <username>
password: <password>
scope: api offline_access
Here is the response received from both the initial token request, as well as each request to refresh the token:
{
"access_token": "<accesstoken>",
"expires_in": 3600,
"token_type": "Bearer",
"refresh_token": "<refreshtoken>"
}
From what I am searching through, it seems that Acumatica uses IdentityServer3 to implement the OAuth API for Connected Applications. The clients are entered through the SM303010 screen where you can set the ClientSecrets and RedirectURIs. The attribute in IdentityServer3 to modify would be AccessTokenLifetime.
https://identityserver.github.io/Documentation/docsv2/configuration/clients.html
It is defaulted as 3600 seconds (one hour) and does not seem to give you any entry point to modify.
I would verify with Support, but if it is not available, you can always request the feature to be added on https://feedback.acumatica.com

REST Validating token in business API generated by authentication service

I have two different REST API’s say Authentication API & Business API hosted in Windows azure.
Authentication API is responsible for authenticating user using WsFederation or OpenID or custom authentication
Business API is responsible for executing business logic. Only legitimate user should be able to access this API.
Client will contact first Authentication API and will acquire the token and then it will pass that token to Business API.
Since client can send any token to business API. Business has to validate the token. It simply cannot trust on the token. Since token Is generated by Authentication API, how business API will validate the token.
What is a standard way to validate the token in such scenario where Authentication API and Business API are hosted separately?
Good References
Principles of Token Validation (Vittorio's blog) - Awesome article, most of the information is generic so applies with or without Azure AD, and it's coming from a very knowledgeable author of course
Manually validating a JWT access token in a web API - This one is specific to validating an Azure AD issued token. Has complete code implementation too. You don't need to do exactly this, because your validation will depend on token format/claims that you use but may provide a helpful reference.
You can look at how token validation is recommended for applications secured by Azure Active Directory as a case study (and may be some other systems as well), then decide what works best for your case.
Brief explanation on how Azure AD example is relevant.. as validating received token is required just like in your case
When you develop any web API (or web app) secured by Azure Active Directory and use bearer token based authentication, the way things flow is very similar to what you explain above with your 2 APIs (just for understanding purpose, your authentication API is doing what Azure AD token endpoints would do.. i.e. provide a valid token).
To access the secure web API, calling application/client first interacts with Azure AD endpoints to get a relevant token for required resource, then it sends a request for actual resource along with the token in Authorization header to the web API. Now, the first thing web API does is to validate this token and only if everything is correct continue with execution to eventually return a response. I hope this matches at a high level with your flow.
What to validate?
1. Token Signature
The key used to sign the issued token is uniquely associated to the issuing authority, so nobody else can issue a token with your Authority's signature.
a. This helps to check that the token was in fact issued by Azure AD (or in your case your trusted STS, using the Authentication API you mention).
b. This also makes sure that since the token was issued and till it reached your web API, no body has tampered with it. If any attempt is made to change any information in the token, the signature will break.
2. Token Claims
This will depend on what claims/information you send as part of the token (for example, if same Authentication API issues tokens for multiple different APIs, then something like audience and issuer might make sense for you as well. Token validity time period using something like nbf and exp below are also pretty generic)
Taking Azure AD issued tokens as example here are the important ones that should be validated:
audience claim (aud), to verify that the token was intended to be given to your application
not before (nbf) and expiration time (exp) claims, to verify that the token has been received within it's validity period
issuer claim (iss), to verify that that token was in fact issued by the said authority. Notice this is a second way, apart from signature for the same purpose and generally both signature and issuer check are used together. (See Vittorio's blog)
nonce, as a token replay attack mitigation
tenant claim (tid), to verify the tenant. This is useful in case of multi-tenant applications.
Sample JWT Token from Azure AD
Actual Value: eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1N... (a long encoded string continues) Decoded Value (you can check this easily using a website like https://jwt.ms or https://jwt.io):
{
"aud": "https://service.contoso.com/",
"iss": "https://sts.windows.net/7fe81447-da57-4385-becb-6de57f21477e/",
"iat": 1388440863,
"nbf": 1388440863,
"exp": 1388444763,
"ver": "1.0",
"tid": "7fe81447-da57-4385-becb-6de57f21477e",
"oid": "68389ae2-62fa-4b18-91fe-53dd109d74f5",
"upn": "frankm#contoso.com",
"unique_name": "frankm#contoso.com",
"sub": "deNqIj9IOE9PWJWbHsftXt2EabPVl0Cj8QAmefRLV98",
"family_name": "Miller",
"given_name": "Frank",
"appid": "2d4d11a2-f814-46a7-890a-274a72a7309e",
"appidacr": "0",
"scp": "user_impersonation",
"acr": "1"
}
How to do token validation?
Make use of standard libraries as much as possible. See the code implementation sample Manually validating a JWT access token in a web API. This one makes use of JwtSecurityTokenHandler.ValidateToken Method (JwtSecurityToken). Your case will depend on your token format/implementation etc.

Authentication with JWT and JSONAPI

I am implementing REST API using the following technologies/approaches:
JSONAPI
JWT token
I want to implement authentication endpoint, it should receive username and password in POST request in JSONAPI format and return JWT token in JSONAPI format.
But I see there are some contradictions that does not allow me to be 100% RESTful:
Let's name endpoint /tokens, because it actually creates tokens. Response would be also resource of type tokens, e.g:
{
"data": {
"type": "tokens",
"attributes": {
"value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjEifQ.ivJ5P23wqVo3w31flg3aOu7er--Ijght_RrBf_MuqsU",
}
}
}
But how about request? username and password are properties of user, but they should be sent to /tokens endpoint. If I send users resource to /tokens endpoint it does not make much sense.
Is there a way around for this, to follow JSONAPI and keep API meaningful?
If I send users resource to /tokens endpoint it does not make much sense.
Why not? REST does not impose that you only send users to a user resource. Sure, when you CRUD operations on a user resource you'll do this via the user resource endpoint.
But to generate a token, it's totally reasonable to send a user resource to the token endpoint.
You could also supply the user credentials via an HTTP Authorization header, or as part of the toplevel meta property of the JSON payload.

How to authenticate for Facebook graph API using standard OAuth 2.0 libraries?

In a project I am using Authentication multiple times for different providers, so I am relying on standard libraries.
I want to establish connection with Facebook yet it provides not completely standard authorization.
To test the connection I am using REST Console in Authorization part of it I place a key and secret and for
Authorize URL I provide https://graph.facebook.com/oauth/authorize
Access token URL - https://graph.facebook.com/oauth/access_token
Request token URL I leave empty or fill it with https://graph.facebook.com/
And what I get bck looks like this:
{
"error": {
"message": "Expected 1 '.' in the input between the postcard and the payload",
"type": "OAuthException",
"code": 1
}
}
So my question is how to get authenticated forming standard OAuth calls?
EDIT
For the moment (testing stage) I found that data can be retrieved using no standard authentication but access_token with appropriate values. Yet sending http request with api key and secret exposed in the request url can not be the right way of ding it.