Confused about Cognito app clients and custom scopes - amazon-web-services

Please correct me if otherwise. OAuth scopes defines an application's access to a user's account while custom scopes define an application's access to a resource server. After signing in, an access token is returned containing the custom scopes, which depend on the query string parameters in the Cognito domain.
Is the purpose of an app client's custom scopes to define its permission to protected resources just to ensure users are logged in from a specified app?
A User Pool can have multiple app clients, each with their own custom scopes. Why not grant all app clients access to all custom scopes? Most apps allow anyone to signup, couldn't users just login in through an app client that has a different set of custom scopes anyway? Is it a least privilege thing? Is it meant for apps that have a restricted sign up, such as paid membership? And if using a web client, the client id is exposed and there's no secret, so how does a client id prevent others from obtaining the id and posing as an app client?
How does this tie in with user specific permissions? Seems like custom scopes are only for resources that are app specific, but not user specific. Do you implement custom logic for authorizing access to specific resources, or can this also be also done with User Pools?
Also, please recommend any resources besides AWS documentation (which I've read) regarding Cognito that really help explain the use cases and entire process.

Related

Does a Service Account have to impersonate a user to access the Directory Api?

I think I might be misunderstanding how Service Accounts work in GCP, as I don't understand why (in my situation) they need to impersonate a user to complete a task.
I need to access some information that is within the Workspace Admin SDK API (for example listing chromeos devices) on my application without prompting a user to log in. I thought the best way to do this was using a service account to do this, so I could upload the details of my service account to my application, and every time I required some data it would do so via this account.
I have created my Service Account in GCP, and then given it Domain-wide Delegation with the required scopes in Google Workspace.
At first when testing this I was getting Forbidden 403 errors because I was not impersonating any user. Once I starting impersonating a user, I was able to get the data I required from the API. I also confirmed that when I removed some of the scopes on the Domain-wide Delegation, I was no longer able to retrieve that data. This means that while I was impersonating a Super Admin, I was only able to get the data for the scopes I had provided the Service Account.
This leads me to the question as to why I need to impersonate anyone in the first place?
Is this just a problem with the Directory API? In their documentation, it states that
Note: Only users with access to the Admin APIs can access the Admin SDK Directory API, therefore your service account needs to impersonate one of those users to access the Admin SDK Directory API. Additionally, the user must have logged in at least once and accepted the Google Workspace Terms of Service.
So my question is: Am I able to make calls to the Directory API as a Service Account without having to impersonate a user? If not, is it possible to make any API calls as a service account without impersonating a user, or is this just a Directory API issue?
Related to this question:
why I need to impersonate anyone in the first place?
The service account allows you to authenticate and be authorized to access data in Google APIs as documented here, by performing domain wide delegation you are granting access the service account to access your account data by impersonating a user from your domain. You can look at a service account as a way to automatize authorization as it can perform changes over several APIs not only the Admin SDK and avoid having the user impersonated to be providing access to a given API each time.
You can make calls to an API without impersonating an user but that would lead to accessing data available to the service account only as it's data belonging to their own, meaning that for example, if you make a Drive API call to create a document using a service account without impersonating it, the file could be created but it will only belong to the service account and you won't be able to access that data as an Administrator the data won't belong to your domain since the service account is different than a user account, you can check more about this in this documentation.
Now related to the last question about impersonating a user, impersonation is a way for you to make API calls on behalf of a user so that user doesn't needs to be providing API access each time that you need to perform changes, this applies to Super Admin users and regular users, this is as well noted in the documentation:
In enterprise applications you may want to programmatically access a user's data without any manual authorization on their part.
Rather than looking service accounts and impersonation as a problem, you could think about it as a way for you to make changes over your users through API without requiring them to give you access to do so. Impersonation allows you to make several changes and can help your organization to automatize several tasks when API calls are needed.
That depends on which resource/method you're using, and which privileges it requires.
For example, you can grant a service account the Groups Reader or Groups Admin admin role, and then that service account can call the methods of the groups resource. No domain-wide delegation required.
But that doesn't work for all resources/methods, and in particular it doesn't work for those that require super-admin privileges. To call these methods, you have to use domain-wide delegation to impersonate a user that has super-admin privileges.

Different access tokens for users using aws Cognito for authorisation

I am trying to provide differential access to services behind an aws api-gateway, lets say simplistically split into 2 user groups user-a and user-b that each can access /routeA or /routeB but not the other.
User Authentication is via Cognito User Pool with 2 user groups defined. Front End is React and Amplify.
I am going round in circles with this having tried a few approaches. Running this decision tree select-auth-method points to using Cognito AuthZ which is fine in itself as I am using Cognito for AuthN.
So far none of the examples/tutorials/articles/videos have demonstrated how to block some users while enabling others. I have tried:
Cognito User Pool Authorizer - identity token based but seems to just AuthZ any logged in user. I could possibly attach IAM Roles to the user groups ?
Custom Lambda Authorizer - Works well on checking for the valid user-group in the Access Token and dynamically creating the required permissions but, some additional latency from a λ and no check that the access token is current. Starts to feel like I am writing code for a system that exists somewhere else?
Cognito OAuth - Spent some time trying to understand this. So I create a Resource Server attached to the Cognito app client and create some custom scopes that I can then reference in the Api-g Authorizers. Fine, but how to I create two different access tokens for the users that have different scopes? So far my understanding seems to suggest that it is another binary AuthZ approach, but articles suggest (but don't demonstrate!) it is capable of granular permissions? I must be missing something.
I also saw this 2017 answer but things may have moved on with better approaches?
I am minded to go OAuth route as it seems more of an industry standard approach and promises much but need a bit of insight as to how to enable different access tokens for different users.
So the answer is that Cognito does not implement the OAuth2 functionality that I need but others do. Given the following excerpt from AuthO docs, this feels like a better solution path...
It would be very useful if we could just restrict endpoints on the cognito:groups that are in the tokens,but this functionality isn't there.
There are a few options that might suit you, one is just put the users in different user pools and create different authorizers for those pools and assign them the routes.
Another is OAuth scopes, you can create two app clients each with different scopes then configure the scopes in APIGW. Note that in this case you need to pass the access token to APIGW not the ID token.
In either case if you are using Hosted UI you will have a problem as you will now have two Hosted UIs and it may not be straightforward knowing which one to display to a user until they have entered their email address.
BTW if you are not using Hosted UI you will be unable to use OAuth scopes.
You can also assign IAM roles to the cognito:groups and allow these access to the APIGW resources you want. This is probably the easiest method although it is not as simple as you would probably like.
The final way I can think of is writing a custom authorizer, I would avoid this if you can, I have done it a few times now and it has never been enjoyable.
Your requirement seems to be to authorise users depending on their permissions, as opposed to needing different types of access token.
I would recommend sending the Cognito access token to the API and receiving it like this in the API:
Level 1: Validate the access token first to check it is not expired etc
Level 2: Consider checking a scope to ensure that the token is for your API
Level 3: Check finer grained claims such as group membership or anything else that makes sense for your scenario. Your API can get groups by sending the access token to the Cognito user info endpoint.
DESIGN PATTERN
This blog post of mine describes the pattern and use of claims caching.
Here is some lambda authorizer sample code, though the same behaviour can be implemented in your API directly and my blog has some examples of this:
Cognito Claims Based Authorization

AWS Cognito User Management

For the last few years, I've built a PHP and MySQL based website where users can submit reprographics and IT requests. I'm hoping to make this cloud-based rather than running it from a local webserver. My initial idea was to have an EC2 instance running as a web server for each company which uses my system, but as the system is PHP session based I'm assuming the security would not be great so I think I need to move towards more of an AWS system using Cognito for user management and the API Gateway with Lambda to do the job of getting the data from the databases. My question is, my current system has an admin console where the admin user can access the lists of users, and assign them permissions (session variables) which allows them access to specific pages. How would I make a webpage where users can manage the users in a Cognito user pool without giving them access to the AWS console.
Implement a Cognito AdminAddUserToGroup operation in your Lambda function for admin users to manage what Cognito Groups your users belong to. Your admins will be the only ones that are able to invoke the API call to the Lambda function because they'll be included in the Cognito Admin Group with appropriate permissions to invoke the Lambda function that you specified as the developer.
Specify permissions of what each Congito Group has access to by assigning roles for each Cognito Group.
You can also decode the jwt on the backend to determine what Cognito Group the user belongs to that made the request and use Amplify on the FrontEnd to manage the FrontEnd's display of content based on the Group (links, etc). More info about that can be found in this thread: How do I access the group for a Cognito User account?
I do not have enough points to comment on the CLI update-user-pool suggestion, but wanted you to know that wouldn't work because 1.) It would impact the entire user pool and affect ALL users in the user pool and 2.) It would make no difference in regards to what your users were able to have permission to access in your application.

AWS cognito: allowing only a certain users (identities) to get credentials

My production environment uses AWS cognito federated identities (AKA: identity pool) for allowing users to sign in with their Google/FB accounts. This is working fine.
However, for my staging environment I want to offer a similar sign in functionality (that is: users sign in in via Google) but I want to restrict the ability to sign in only to a specific whitelist (of, say, #gmail.com accounts). This is because the staging environment should only be accessed by team members and a bunch of trusted users.
My question is this: is it possible to define a Cognito identity pool that allows only the whitelisted users to sign in? if the answer is "yes", then how?
I know that I can do the whitelist checking at my backend (that is: at the backend of my staging env. I will reject every request not coming from these whitelisted users) but this is a bit unclean. In particular, I want the rejection to happen as early and possible and, ideally, to be carried out by cognito itself, and not by my backend.
Clarifications:
I mentioned a list of #gmail.com accounts as the whitelist. I am open to any other mechanism for defining the whitelist.
In a way I am asking whether I can have user directory functionality (in particular: determining if a user is in a certain group of users) with an cognito identity pool.
The purpose of the Identity pool is to provide access to authenticated identities. Therefore, this resource cannot manage users (ie: white listing a user group).
There are two ways to do this:
Link 3rd Party Identity into a User Pool and white list by User Group. Your user group will have a Roles and permission it will assume that will allow your test users to have the functionality they need without allowing other users who log to have that functionality.
Manage users from the 3rd Party Identity - I am not an expert at Google authentication.. but some OpenID providers allow you to create user groups with different access roles. This is an example for Google.
You can invoke a trigger and execute a lambda function when the user submits their information to accept or deny the sign in request.

Oauth2 grant for server-to-server communication

I'm working in a microservice architecture, which has its own oauth2 provider in order to allow services interaction.
I need to develop a service that is granted to access users' resources in order to perform internal tasks on user accounts. Since the service needing to access user resource is an internal one it's not a viable solution to ask the user to allow access to their own resources.
I'm concerned about the choice of picking the right grant to perform this tasks, as the client_credentials seems the right one, it also seems to be used to only allow to only update service data, instead of accessing user resources. Another solution I thought is to automatically provide the authorization code at users signup, as if the user has clicked an "allow" button, and then perform requests with that code grant. The downside here is that I have to create new authorization codes each time a service with that needs is created, but it seems to be a more clear solution (as auth code for user XXX only allows to access resources of user XXX).
I also understand that implementations are different as the standard gives a lot of flexibility, but
Which one, in your opinion, is the appropriate solution? How would you handle it? Would it be more clear to say, "statistic service" is allowed to access all users resources or "statistic service" is granted by all users to access their resources?
As you state this is an internal use case where you control the resources protected by your Resource Server, the Authorization Server and the clients accessing the resources so you may choose to use client_credentials for accessing user data.
It compares to (or actually is) a "service account" that may be used to manipulate user data. If that service is under your control and you trust it i.e. you trust that it does not leak it's credentials to other parties and does not abuse its powers it is OK. Since you also control the client it would not be a problem.