I use serverless-framework with aws lambda and aws cognito. I have set up a user pool and registered the app. I can login in the login ui and get the code and then exchange the code programmatically for tokens.
But how should I send the tokens from the web client to the aws lambda?
I can use the program Postman or curl but I need to use a web client (http browser). How should I set the header with the token?
After you receive the token from Cognito Token endpoint, you can store it in the Browser storage (e.g; LocalStorage, SessionStorage, ClientSide Cookies) using JavaScript and send it in Authorization header for API requests (Ajax requests).
You can use AWS Amplify JS library to simplify the authentication and refreshing the token.
Note: One can argue that it is not safe to store the token's in Browser Storage, but if you look at AWS Amplify JS library, it uses LocalStorage to store both id token and refresh token.
Related
I am writing a Dash app that requires the user to login using Basic Authentication. The user credentials are then sent to the server in the request header with every request.
What I would rather happen is that a JWT is produced on the client-side and sent in the request header (replacing the basic auth credentials in the request header) as it is much more secure. However, I am having trouble working out how to replace the request authorization headers in Dash.
The flow would be:
User inputs their credentials;
Credentials are used on client-side to grab JWT;
JWT is sent in request header with each request.
To be precise, I am unsure how to carry out step 3 above in Dash.
I am currently using dash-auth for my basic authentication, Python 3.9, Dash 2.0.0.
I would like to use boto3 to get temporary credentials for access AWS services. The use case is this: A user in my Cognito User Pool logs in to my server and I want the server code to provide that user with temporary credentials to access other AWS services.
I have a Cognito User Pool where my users are stored. I have a Cognito Identity Pool that does NOT allow unauthorized access, only access by users from the Cognito User Pool.
So here is the code I am starting with:
import boto3
client = boto3.client('cognito-identity','us-west-2')
resp = client.get_id(AccountId='<ACCNTID>',
IdentityPoolId='<IDPOOLID>')
However, just running these three lines of code throws an exception:
botocore.errorfactory.NotAuthorizedException: An error
occurred (NotAuthorizedException) when calling
the GetId operation: Unauthenticated access is not
supported for this identity pool.
Since my Cognito Identity Pool is not set up for unauthenticated access, it seems that I cannot call get_id until I somehow authenticate somewhere.
How do I solve this? What exactly do I need to do to authenticate so I can call get_id?
UPDATE: Looks like I need to pass a Logins field and data to the get_id function call, but to do that I need the login JWT token. If I am running this inside a webapp (eg a Django backend) where I use the AWS Cognito prepackaged login screens, then yes I can get this from the homepage URL after redirection from successful login. But now I am writing some test scripts that have nothing to do with a website. Is there a way to use boto or boto3 or some other python package to login with username and password and get JWT token?
Just to add to the answer from Arka Mukherjee above, to get the token I do this:
auth_data = { 'USERNAME':username , 'PASSWORD':password }
provider_client=boto3.client('cognito-idp', region_name=region)
resp = provider_client.admin_initiate_auth(UserPoolId=user_pool_id, AuthFlow='ADMIN_NO_SRP_AUTH', AuthParameters=auth_data, ClientId=client_id)
token = resp['AuthenticationResult']['IdToken']
Here I have to use the username and password of the Cognito user, client_id is the app client id for the app client that I set up thru Cognito, and user_pool_id is the user pool id.
Note that my app client has this option checked/selected: Enable sign-in API for server-based authentication (ADMIN_NO_SRP_AUTH) and I created that app client with no secret key (apparently that is important for web clients especially).
To pass the Cognito User Pool JWT Token, you would need to use the Logins Map in the GetId API call. You could try the following Python code out on your end, after replacing the necessary placeholders.
response = client.get_id(
AccountId='string',
IdentityPoolId='string',
Logins={
'cognito-idp.<region>.amazonaws.com/<YOUR_USER_POOL_ID>': '<JWT ID Token>'
}
)
If you do not provide a Logins Map, Amazon Cognito treats the authentication event as Unauthenticated, and hence, you are facing this error.
I've been able to obtain Access Token for my Aws Cognito user (using this).
But I can not figure out how generate an authenticated request with it for an Api Gateway with Cognito authorizer.
Can someone please share a sample snippet?
The problem should be in API Gateway and Cognito User Pool configuration. You could use id token instead of access token in header request and it should work if API Gateway and Cognito User Pool have a basic configuration.
If you prefer to use access token, you must check some details in configuration of API Gateway and Cognito User Pool: there shall be a
Resource Server in Cognito and
at the same time there shall be defined OAuth Scopes in Method Request of API Gateway coherently to Resource server.
You can find a good explanation about this configuration in this question:
AWS API Gateway - using Access Token with Cognito User Pool authorizer?
I suggest you this last way and to use access token.
About the request header, it's enough to put 'Authorization': YOUR_ACCESS_TOKEN.
Check to have added 'Authorizarion' in Token Source when you have created the Authorizer in API Gateway.
Put the access or id token obtained from the Cognito user pool in the Authentication header when making an API Gateway request
My answer assumes that you have Cognito Authorizer, not Lambda Authorizer. When you create the Cognito Authorizer, you give the name of the authorization token in the Token Source field. For example, auth_token.
To call the API resource to which the authorizer is screwed, you need the IdToken of the user who is currently logged in.
With the help of lambda functions, you can organize user login with obtaining IdToken, AccessToken, and RefreshToken. IdToken and AccessToken don't live long. You can make a lambda function that sends a RefreshToken to the User Pool and gets back the fresh IdToken in response. Read more about all this stuff here.
So, you have a fresh IdToken, as well as the name of the token that the Cognito authorizer requires. In my example, it is auth_token.
import requests
import json
CustomHeader = {'auth_token': "very-long-id-token"}
r = requests.post(
"https://xxx.execute-api.us-east-1.amazonaws.com/beta/user/function-for-auth-users-only",
data=json.dumps({"whatever_you_need": "your_value"}),
headers=CustomHeader)
print(r.json())
I went through the Flask OAuth api, and its pretty clear how to do authentication for a web app. The web app gets redirected to the authentication provider login page, where access is granted, and returns back to the web app with a token.
However, for web api scenarios, where a client is pre authorized to call the web api, the request will have a Bearer token along with the call. Is there any example on how to validate this token? I see apis like validate_access_token() in the OAuth2 library, but I cant see any examples where people use it for web apis.
I use Azure AD for authentication, and have created an AAD application, and am able to get a token from it through the adal package on the client side (with the clientId and clientKey from AAD). But I havent been able to authorize it yet on the web api side, because it seems most scenarios look at web app authentication and not web api scenarios. Any ideas on how to authenticate on server side?
I have an app which amounts to a Python script, running on the user's phone, and a JS client, running in the user's browser. The Python script sends messages to App Engine as HTTP requests. The server then pushes the messages to the JS client.
The problem is authentication: The server can easily use Google Accounts to authenticate anything coming from the JS client as being sent by a particular user, but I do not know how to get the Python script to make HTTP requests which will also authenticate.
Any ideas?
According to its homepage, httplib2 has support for Google Account authentication, maybe that may help you?
Can you use OAUth to authenticate with Google, then use the OAuth token to ensure the messages are legitimate?