JWT and identifying caller identity - web-services

I have problem understanding how to properly protect services using JWT in terms of identity of a caller.
I'm trying to build a authentication/authorization service which would be used by multiple other services.
Let's say, for the sake of simplicity, that we have mentioned Auth Service, together with Service A, Service B and Service C.
Service A, B and C are able to verify that tokens were created by the common Auth Service (have public keys).
In the payload of the Token generated for each of the services after Authentication, Authorization rights are listed.
So, something like this:
Agenda:
Service A needs to access service B. Service C must not access service B.
Use case:
Service A logs in with the credentials it essentially has for accesing Service B, receiving JWT with payload saying it grants righs for accesing Service B.
Service A makes a request to Service B. Service B validates the token. Service B validates that the Token is intended to be used on itself from the payload.
All good.
Now, what I want to prevent is:
(Step 1 the same as in the use case above)
Service C hijacks the JWT created for Service A.
Service C access Service B resources.
Basically, the question is, how to prevent that one token, in the end, opens all the doors of the services authed by the common auth service?
Maybe it goes out of the scope of JWT, but somehow, I feel as if, I'm missing some crucial point that could prevent this.

Typically two tokens would be issued to Service A (aka. the "Client") in this use case, one for accessing Service C and one for accessing service B.
Each token would include a so-called "audience" field that specifies who the intended recipient is and it is the recipient's duty to check that field. In a JWT that field would be aud and it would contain some identifier that references Service C or B.
Service A would only ever send token B to Service B and token C to Service C. Thus Service C cannot get hold of token B and upon using token C against service B, the audience check performed by service B would make it reject token C.

Related

Usage of ID tokens and Access tokens, with external Authentication, AWS backend and graphql language

I am currently working on building a mobile app which will require the users be authenticated, and have them specific privileges on what they can do (for example, a logged in user will only be able to manage some of their data held in the backend database).
I think I do understand the differences between ID token (user identity) and Access token (for authorizing between the mobile phone client and the back-end), but I am not sure what I intend to do conforms to the best practices regarding authentication and authorization.
Let me summarize what I am planning to do:
front end will be a Flutter/Dart mobile app
authentication will be done through Google Firebase Authentication service
my back end will be hosted in AWS:
API Gateway will serve a unique graphQL endpoint
API Gateway has an associated Lambda authorizer function which processes requests prior to the actual "application" Lambda functions
"application" Lambda function serves GraphQL requests (using python ariadne library), including authorization business logic
Database is a managed PostGreSQL inside AWS
The authentication / authorization workflow is as follow:
Not all of this has been implemented yet, but on the paper I think it could work.
However, it goes against several good practices regarding token usage:
the ID token is sent along an API call which is advised against (see this nice auth0 blog post)
I make no usage of access token between the front end and the back-end (could the AWS policy generated at step 5 fullfill this role?)
I do not leverage the audience claims in tokens
Note: as GraphQL exposes a single endpoint, I am not sure of what the content of the access token should be
I am new to Authentication / Authorization and would gladly have some insight regarding the best way to actually make everything work as per best practices, accounting to the following contraints:
authentication is outside of AWS
the APIs are GraphQL

Token exchange grant support in AWS Cognito

I am working on a cloud native microservices based application deployed in AWS. This application should use a OIDC based IdP (preferably AWS Cognito). The authentication and authorization flow are as follows. Once the user logs in using authorization code flow, the IdP generates one ID token and access token. The access token is sent to the backend services for the backend calls. The backend service can fetch the user information through /userinfo endpoint if needed. Additionally, the access token has the required group claim and the scopes to determine if the right access is present.
Now if the backend service needs to call downstream backend internal microservices on behalf of the logged in user, then should I create a
new token with client credentials grant with a reduced scope needed for the service call? or
Should I send the initial access token of the user only?
In the first case the user context is lost in the new access token and if the downstream service requires the user context, then how will the downstream service get the user information?
In the second case the downstream service is not called with the exact specific scope needed for that service and is not security best practice.
However, there is also one more grant call exchange grant (https://www.rfc-editor.org/rfc/rfc8693.html) which supports creating a new access token with the user context from the initial token without relogging in the user (delegation mode in https://www.rfc-editor.org/rfc/rfc8693.html). Is it supported in AWS Cognito? If not, then how can I achieve the same functionality if I use AWS Cognito?
It kind of depends on the level of trust between microservices. By default, if they are part of the same unit, aim for this type of setup:
Orders microservice, requires an orders scope
Shipping microservice, requires a shipping scope
Customer website, uses scopes orders and shipping
You can then flow the user identity securely, if Orders calls Shipping, by forwarding the access token. Meanwhile each API verifies the JWT on every request and checks for the scopes it needs.
Each API should also check for an audience claim has the expected value, representing a set of related APIs, such as api.example.com. I believe currently though, AWS Cognito does not issue an audience claim to access tokens.
If Shipping is a less trusted subdivision of your company, token exchange would be more appropriate. Eg if you have concerns about a Shipping service abusing Orders privileges.
Avoid over-reliance on scopes, or too many of then. Use claims for the main authorization. In Cognito you can look up these values after verifying the JWT but before your API creates its claims principal
Cognito only has quite limited support for more advanced token behaviour, such as issuing custom claims, reference tokens, or token sharing techniques. If you need them, the preferred option is to choose an authorization server that supports the standards.

Google Identity Platform OAuth server

I want to user Google Identity Platform as the CIAM solution for our GKE-based cloud service. We have a requirement to allow 3rd parties to access our cloud APIs using credentials they obtain via OAuth.
For example, our cloud service provides APIs that Google Assistant or Amazon Alexa can access on behalf of our users. Therefore, we want to provide an OAuth-based token manager that uses the identities of our customers as defined in the Google Identity Platform.
Is this type of OAuth service possible using Google Identity Platform, or the underlying Firebase service that drives it?
Based on the documentation for Google Assistant, you will need to implement your own OAuth2 endpoints. In the authorization code flow, you need two endpoints:
The authentication endpoint needs to sign in the user and get their permission to allow the third party (eg. Google) to call the customer's API on their behalf. If the user gives permission then they return an authorization code - which could be implemented by creating a custom token with Cloud Identity Platform.
Token exchange endpoint is also needed, which has two functions. The first is to exchange the authorization code created by the first endpoint for a refresh token and an ID token. The second is to exchange a refresh token for a new ID token. Both of these functions can be delegated to Cloud Identity Platform.
Additional note:
I would suggest to use custom claims to ensure that these tokens can only be used for the intended purposes, ie. to perform actions which the Google Assistant needs to do. Users shouldn't be allowed to perform other actions, eg. changing the user's password or providing authorization codes to other third parties.
Also make sure that this endpoint can't be used by malicious third parties. For example, you can check that the redirect URL provided matches what is expected, since this is where the authorization code will be sent to.

WSO2: Unable to generate access_token with scope=apim:subscribe

I am using WSO2 Identity Server-5.10.0 and API Manager-3.2.0.
Have created application in devportal and subscribed the APIs to this application.
In Identity server have enabled Role based scope validator for this service provider.
using below API to generate token:
https://IS_host/oauth2/token
After enabling Role based scope validator unable to generate token with scope=apim:subscribe and giving the error invalid scope.
user is assigned with the role -Internal/Subscriber
We are creating Application in Devportal and subscribing APIs to this Application.
We wanted to list the scopes associated with APIs which are subscribed to Particular application. hence we are calling below API to list scopes based on applicationId
https://AM_HOST/api/am/store/v1/applications/{applicationId}
To invoke this API we need to generate Token with scope: apim:subscribe, But after enabling Role based scope validator we are unable to generate token with apim:subscribe.
if we disable Role based scope validator, user will be able to generate token for all the scopes irrespective of roles associated with user.
The apim:subscribe scope is a reserved scope for API Manager REST APIs. Hence, it is not required to create an Application from the Devportal to generate the Tokens with it. You can perform a DCR operation straight to the API Manager to register a client and generate the Access Tokens with the API-M reserved scopes.
Further, I believe that you have configured the IS as the Key Manager by following IS-Connector approach. The Role Based Scope validator feature requires a set of DBs to be shared among the servers.
Hence, the best way to generate the API-M specific scope tokens would be as following
Perform DCR operation to the API Manager instance (not the IS)
This creates a client in the API Manager using the Resident Key Manager of the API Manager and responds back with the consumer credentials (client ID and secret)
Perform Password grant to generate the token using the received consumer credentials
You can learn more on performing the DCR and subsequent calls in Devportal REST API Docs
Hope this helps you to overcome the reported behavior.

Amazon Cognito: How to pass credentials to server-side application

I have a client side application (developed in Java, not Android) that authenticate a user with an Amazon Cognito User Pool. To make things clear: that application display a username/password entry dialog, then authenticate with the Cognito user pool service using the SRP method; potential challenges are handled in that dialog (device id, password must be changed, two factors, etc). In the end, I have a series of tokens that allow the program to use AWS services with the user's credentials.
Now, I need the client application to communicate with a custom server side application. The client will have to prove its identity to the server application, which will then communicate with more AWS services. Here, I have two distinct use case:
1) The server only needs to know who the client-authenticated user is (in a safe manners, but without impersonating the user).
2) The client needs to delegate some or all of privileges of the user to the server; the server will then perform some actions on AWS services under that users behalf.
The server side application will most likely be developed in Java, running on an EC2 machine. I'm only interested in user authentification through the Cognito user pool source (that is, I have no interest in Facebook/Google/OpenID-based authentication flows).
It seems rather easy to achieve both objectives in very unsafe manners: just have the client application send to the server all the tokens it has been granted. But this is obviously not the way to go.
Yet, I'm having a hard time figuring out from Cognito User Pool/Cognito Identity Pool/IAM/STS documentation how this can be correctly achieved. I would expect for example the possibility for the client application to be able to generate some kind of "delegation token", which can be passed to the server; the server should then be able to validate that token and extract identity information from it (satisfying #1), or to impersonate the identity corresponding to the token in order to perform calls to AWS services (satisfying #2). Or maybe I'm thinking this incorrectly?
What you are pointing at is OAuth 2.0 code grant flow which is not currently supported by Amazon Cognito.
The current available safe way to do this is to pass the id token from the client to the server and then validate that token and extract identity information from it. This proves the identity of the caller as you can validate the signature of the id token.