I've been playing around with the new Cognito User Pools to manage user accounts and I'm trying to build a system where users have to log in to use the system, and new users can only be added by existing users (ie no public signup).
Currently there seems to be no way of stopping an unauthenticated user from calling signUp. I've changed it so that the Pool doesn't allow unauthenticated users but this doesn't seem to make any difference (as setting the accessKeyId and secretAccessKey to anything makes it run).
Have I missed something?
First of all, I think you are confused between an Identity Pool and a User Pool. Cognito user pools do not have a concept of allowing or not allowing "unauthenticated" access, identity pool does.
Now to answer your actual question, Cognito user pools is an authentication provider which implicitly means that the sign up process has to be unauthenticated. There is no way to authenticate a sign up call.
Although, if your use case is to build some sort of an invite based sign up process you can use the Lambda trigger functionality with User Pools and validate each SignUp call in the PreSignUp trigger. This validation could check the existence of a valid invitation code in the validation map and accept the call only in that case.
After a long time, this has been solved by the AWS team. They have now added in an option User sign ups allowed? Setting this to: Only administrators can create users means that no-one can just sign up to the user pool.
In order to add a user now you will need to use the aws cognito sdk and the various functions starting with 'admin' (eg. adminAddUser).
Related
I have a web application which uses Cognito to allow users to login. Cognito uses external provider (Okta). When user login first time user entry is created in user pool. I also have second application which has to use the same user pool, but because of specifics of this application I have to use email and password authentication.
I would like users to receive an email asking them to set (reset) their password when they first log in web app. What's a best way to achieve that?
As far as i know it's impossible to set password for EXTERNAL_PROVIDER users, but I can accept creating new (duplicating) users. But still I'd like to ask about best way to do this.
Instructions below are for migrating between cognito instances, but you might find them useful.
there is only one way to get this done is migration lambda trigger. In short:
create new cognito
create migration lambda
add this lambda as a trigger to login and/or forgotten passwords
point users at cognito (this might not be necessary in your instance)
upon login, Cognito will check locally and if user is not found, will use the trigger to check programmatically in another source.
If authentication is successful, old cognito will return object with all properties, incl passwords, which you can then insert into new cognito.
more info here: https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-lambda-migrate-user.html
Background
I am using the Amplify Framework(javascript) for Register/Login in my frontend website.
Register
Auth.signUp({
username,
password,
attributes: {
email: email
}
})
Login
Auth.signIn(payload.username,payload.password)
Every time user login, the cognito id token will be stored in localStorage for accessing API in API Gateway.
This is my API Gateway api setting.
Every successfully logged-in user can call ALL api, for the current design.
Question
Now I want to do role-based permission control on calling the api, e.g. role banner_admin can only call /banner api, while role equipment_admin can only call /equipment api.
After some research, it seems Identity Pool is able to achieve this. But I don't want to change my Login Flow.
Can someone provide the fastest and convenient way to achieve the role-based permission control in my application? Is it possible to NOT use identity pool?
Yes, it's possible to do this without using Identity Pools service.
Actually, Identity Pools is not one to use for this purpose..
It's just exchanging the temporary credential to the authenticated or unauthenticated user to access your AWS resources..
You should use Groups supported by Cognito User Pool service for this purpose.
Once the user would be authenticated by Cognito, the claims he's get will include group information he belongs to(If you added the user to a specific group in User Pool).
You can handle the permission based on this group.
Upon the post confirmation Cognito event, You can trigger your lambda function, then there you can add the user to the corresponding user group in background.
I am an AWS newb, so please go easy on me :)
I have setup a proof of concept to proove out an authenticated API backed by lambda with the following components.
API Gateway -> backed by Lambda
Federated Identities backed by AWS Cognito UserPool
I have the authorizer setup in the API gateway to use the IAM role which is being provided by the Federated Identity pool.
I can see the identity (ap-southeast-2:<GUID>) coming through into the gateway ( using this in my integration request mapping template "$context.identity.cognitoIdentityId" ) from https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-mapping-template-reference.html#context-variable-reference
From either the gateway or lambda how can I resolve the 'ap-southeast-2:<GUID>' back to the source identity which resides in the user pool. (E.g. Pull one of the custom attributes from it)
Other information if relevant, i'm using Amplify-AWS for the client calling into the API Gateway.
TIA.
As you're noticing, Cognito as an identity provider is not the same as Cognito as a user pool.
Federated Identities provide a way of giving someone identified access to your AWS resources. The identity_id the identity provider gives you can almost be thought of as a tracking code. CIP (Congito [Federated] Identity Provider) allows you to get an identity id by signing in through any number of providers (not just the user pool), and even by not signing in at all.
User Pools give you a way of managing users for your application (i.e. a set of usernames, emails, passwords, etc).
This is the reason getting from identity_id back to the user pool user is hard (because, there's no guarantee it is a user pool user, it could well be someone from Facebook).
From what you've said, however, the assumption that said identity_id came from a UserPool authentication is safe. This means you have two options:
The official way will be to use identity:GetOpenIdToken to convert identity_id (you can ignore the logins part of the request) into an OpenId token. You can then use this token against the userpools:GetUser end point. There's a few pitfalls here, like ensuring you authenticate with a scope that allows you to see all the attributes you care about.
Curiously, however, the value of cognitoAuthenticationProvider is not opaque, and can (unoffically) be decoded:
// Cognito authentication provider looks like:
// cognito-idp.us-east-1.amazonaws.com/us-east-1_xxxxxxxxx,cognito-idp.us-east-1.amazonaws.com/us-east-1_aaaaaaaaa:CognitoSignIn:qqqqqqqq-1111-2222-3333-rrrrrrrrrrrr
// Where us-east-1_aaaaaaaaa is the User Pool id
// And qqqqqqqq-1111-2222-3333-rrrrrrrrrrrr is the User Pool User Id
The above example, with more details about how you can then use this with userpools:AdminGetUser can be found here: https://serverless-stack.com/chapters/mapping-cognito-identity-id-and-user-pool-id.html
I don't understand auth. vs. unauth. user access within AWS Cognito. While learning about Cognito I came across several articles on the Internet and questions here within Stackoverflow concerning this and I'm just not grasping the concept.
I'm gathering that a simple use case for unauth. user access within Cognito is when we have users who need to access some AWS resource(s) who have an account but aren't "logged-in." But how is this possible? In other to get an access token, wouldn't you need a valid username and password? If by unauth. we mean a user who has a valid access token but can't access some resources [based on some user pool parameter], I suppose that makes sense, but I don't understand how Cognito works in this regard.
I've searched for hours on this w/o grasping this concept and I really just need a little help from the community if anyone would be willing to share.
UPDATE: What's confusing to me is that "unauth." is a non-logged in user already, no? Why do I have to or want to get an access-token for a non-logged in user? What is the purpose of this?
Something that is confusing when starting out with AWS Cognito, is that it is actually two services. Cognito User Pools is a user store that authenticates users and Cognito Identity Pools authorizes users.
Unauth:
When referring to a unauthenticated flow, you're skipping the authentication process and really just authorizing with an identity pool. To do this in code, you setup a credentials provider, and make a call to GetID. This generates an identityID in the identity pool and retrieves authorization tokens that give access based on the IAM role for unauthenticated users. Example here
Auth:
Now for the authenticated flow, before you authorize with the identity pool, you have to have authentication tokens. These can be retrieved by authenticating with a third party (Facebook for example), or with a Cognito User Pool. You authenticate with those services by providing a username/email and a password. The tokens delivered by those services can then be "passed" to a credentials provider. When done this way, authorizing with the identity pool will return access tokens that give access based on the IAM role for authenticated users. In addition, a user can "log out" and later "log back in" and they will be able to receive the same identity ID that was generated for them the first time they authorized with the identity pool.
I hope that all makes sense. I'll give an example of why you may combine the two
Example
Let's say we're building a web platform that lists events around our city. This platform needs to:
Store events in a database
Allow city organizers to add events to the database
Allow residents to view the events
We wouldn't want the residents to have to login to view publicly listed events, so when they visit the event's page of our website, unknown to them, they actually authorize with an identity pool. Thus they are provided unauth IAM role access to make a GET API call to our database, to retrieve the events.
Of course, we don't want just anyone adding events to the database. So for city organizers, there is a login form. This login form takes a username and password to authenticate them with a user pool. The user pool tokens are then used to authorize with the identity pool, giving them auth IAM role access to make a POST call to our API, allowing them to add events to our database.
I want to integrate a pretty standard functionality: give option to user (mobile and web) to either login with email/password or with facebook (google) account with RBAC (different users may have different roles, like users, moderators, admins, creators, etc). Here is basically what I want from sign in:
I went through a number of AWS tutorials and other materials. I got some grasp on how to implement it, but I still don't have a full picture. Hope someone can help me here.
Here is my current understanding (please correct me where I'm wrong).
1) For the email/password signup/signin I use a User Pool. When user signs-in I call authenticateUser (I'm using JS SDK):
cognitoUser.authenticateUser(authenticationDetails, {
..
})
where onSuccess
I store identity, access and refresh tokens, so, user
doesn't have to enter his credentials every time
Because users will be accessing AWS servicess (e.g. S3) I exchange idToken to AWS credentials
Store AWS creds in LocalStore for further use, when access resources
2) For the facebook sign-in I use Federated Identity
get a facebook access token
with fb token get a cognito identity
exchange a cognito identity to AWS creds and store those in LocalStore
Questions:
Q1. Is it valid and fairly complete logic for sign-up/sign-in? Did I miss anything?
Q2. How should I store facebook users? Can I do it in User Pools? I have impression that it's not possible, but that means I have 2 different user directories: one in UserPool and another one in another place (lets say in DynamoDB)
Q3. If I have to store users in different places (UserPool and DynamoDB) that means I have 2 users for essentially one user, who first registered with email/password and then decided to use facebook - this is inconvenience for both me as app admin and user. How to deal with this situation?
Q4. How to manage groups for users, who signed-in with facebook token (like users, moderators, admins, creators, etc)?
Q5. How should I restrict access to resources other than AWS for facebook signed-in users?
Q6. Any working example for this?
Thanks!
We added support for Federation through Facebook, Google and LoginWithAmazon for User Pools. This will create a user in user pool when a user logs in with federation. You can also capture the attributes from the identity provider using the attribute mapping feature.
Also if you use the app integration feature, Amazon Cognito User Pools wil generate a sign-in page like this for you.
Steps to SignIn/SignUp with a social provider through Amazon Cognito Console:
Configure a domain for your user pool like .auth..amazoncognito.com
Add any social provider and configure attribute mapping.
Enable the provider on the App Client.
Configure the callback URI, OAuth response type and allowed scopes.
Access your hosted UI at https://.auth..amazoncognito.com/login?client_id=&response_type=&redirect_uri=
Click on the button to SignUp/SignIn with Facebook (or your provider).
Authenticate with the provider, you will be redirected to the callback URI with tokens/code.
Check the newly created user in Amazon Cognito console.
I'm human and may have missed something, but that sounds pretty good to me.
You can't store a federated identities login in user pools. Thing of user pools as another identity provider, just like Facebook is. Dynamo (or something else) would be the way to go.
If a user logged in with both, linking those logins, you might want to consider avoiding user pools attributes entirely and only using dynamo. With two logins linked, Cognito federated identities only requires one login token to proceed, but user pools requires it's login token to see/update attributes. The user would have to login with the user pool to touch those attributes, it'd get messy.
I don't know that this is supported out of the box, like it is with user pools. You might have to do this using your hypothetical user database described above.
You can also link your user pool to Cognito as a provider, much like you do for Facebook. That's how you exchange an id token for credentials.
No official example from the service, though I can't speak for others.