I am looking to use Cognito to implement full server side authentication flow. Due to requirements of my app, i need to control registration / sign-in / password-reset etc, on the backend instead of front end.
Iv been reading through the documentation and experimenting for hours to no avail.
i have set up server side credentials in which AWS Cognito states
Confidential client
A server-side application that can securely store a client secret. Cognito API requests are made from a central server.
I have attempted to use #aws-sdk/client-cognito-identity-provider to create the requests that i need but have had no such luck and the AWS documentation is convoluted at best.
This artical Seems kind of close but mentions nothing about client secrets.
Is what I want to achieve even possible, and if so can someone point me to some documentation on how to do this or any sort of example
We're looking to leverage AWS Cognito for authentication with an architecture that looks like:
client (browser) -> our server -> AWS Cognito
With various configurations set, initiateAuth seems no different to AdminInitiateAuth and so I'd like to understand when under these configurations if it matters whether one is chosen over the other.
It seems that when I create an app with a client secret and use initiateAuth, it seems to be almost the same integration experience as adminInitiateAuth that uses the ADMIN_NO_SRP_AUTH auth flow. The latter does not even require AWS credentials as stated in the AWS documentation. My integration with Cognito is as below:
initiateAuth:
const payload = {
AuthFlow: "USER_PASSWORD_AUTH",
ClientId: cognitoClientId,
AuthParameters: {
USERNAME: username,
PASSWORD: password,
SECRET_HASH: generateSignature(username)
}
}
const response = await cognitoClient.initiateAuth(payload).promise();
adminInitiateAuth:
const payload = {
UserPoolId: userPoolId,
AuthFlow: "ADMIN_NO_SRP_AUTH",
ClientId: cognitoClientId,
AuthParameters: {
USERNAME: username,
PASSWORD: password,
SECRET_HASH: generateSignature(username)
}
}
const response = await cognitoClient.adminInitiateAuth(payload).promise();
You can see the difference is the different AuthFlow values, calling different methods and ADMIN_NO_SRP_AUTH requiring the UserPoolId parameter which seems superficial to me.
We are also generating the signature based on the client secret which is something that we would handle securely.
I understand that you would like to know the difference between the InitiateAuth and the AdminInitiateAuth API calls in Amazon Cognito.
To clarify the usage of the API calls:
InitiateAuth is a client/browser side API call, and the API call does not need any sensitive credentials to give a challenge and other parameters.
AdminInitiateAuth is a meant to be run in the server side, and the API call always needs developer credentials to give a successful response. This is because the API call is an AWS SigV4 signed API call.
Furthermore, both the API calls support different Auth Flows as specified below.
InitiateAuth supports the following Auth Flows:
USER_SRP_AUTH
REFRESH_TOKEN_AUTH
USER_PASSWORD_AUTH
CUSTOM_AUTH
Kindly note that the AWS CLI documentation [a] currently states that ADMIN_NO_SRP_AUTH is a possible value. However, I have tested the API call on my end and I can confirm that the documentation for the CLI is currently incorrect.
UPDATE (12/09/2019): It looks like after this answer was written, Amazon Web Services has updated their documentation to the correct possible values. The documentation now states the following:
ADMIN_NO_SRP_AUTH is not a valid value.
AdminInitiateAuth supports the following Auth flows:
USER_SRP_AUTH
REFRESH_TOKEN_AUTH
CUSTOM_AUTH
ADMIN_NO_SRP_AUTH
USER_PASSWORD_AUTH
Example use-case of InitiateAuth: If you want your users to authenticate into your web application.
Example use-case of AdminInitiateAuth: Any use-case that needs server side authentication or access based on specific AWS Credentials to filter that only specific IAM users can authenticate using Cognito.
As stated by george earlier, InitiateAuth would be ideal for your use-case as your application is a client side application.
Additionally, if you are concerned about security, you could use the USER_SRP_AUTH with InitiateAuth. For more information about using the USER_SRP_AUTH flow in your production code, you could refer to the following NPM documentation[b].
References
[a]. https://docs.aws.amazon.com/cli/latest/reference/cognito-idp/initiate-auth.html
[b]. https://www.npmjs.com/package/cognito-srp
initiateAuth and adminInitiateAuth do a similar thing, however, they have different use cases and flow.
initiateAuth is used when you have an end user client app. The user enters their creds and they are sent via Secure Remote Password Protocol. If the flow succeeds the end user gets a token back and is allowed access. This flow is used by the Android, IOS and Javascript SDKs because it's to do with the client side.
adminInitiateAuth is used when you don't have a client end user app but a secure back-end app using Java, Python or some other backend language. This method does not accept username-and-password user credentials for admin sign-in but requires AWS credentials.
In your case, if you had a client app ---> Cognito and use for example Android SDK or Javascript SDK directly then you should use initiateAuth from within the SDK passing the user credentials. However, browser -->back-end--> Cognito meaning you have a dedicated back-end so in your case you should adminInitiateAuth. More info here
AdminInitiateAuth only exists for one reason: so you can avoid the hassle of SRP in your server side code while still requiring client side code to use SRP.
SRP is more secure, but annoying/inconvenient to implement. Also, if you're writing code that runs on the server, a lot of the benefits that SRP provides are irrelevant anyway (your code is running in a secure, protected environment).
If you set up a Cognito app client like this:
[X] ALLOW_USER_SRP_AUTH
[ ] ALLOW_USER_PASSWORD_AUTH
[X] ALLOW_ADMIN_USER_PASSWORD_AUTH
... then any untrusted/public client side code must use SRP, but trusted server side code is free to use the plain old user/password flow. (Of course the server side code has to have AWS credentials in order to enjoy this privilege)
You're absolutely spot on though that the two are pretty much equivalent in functionality with some superficial differences.
I too spent quite some time researching scarce documentation on the topic of
when to use AdminInitiateAuth vs InitiateAuth.
https://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-user-pools-authentication-flow.html is supposed to help, but I find it poorly structured and very confusing.
From my understanding, you're right, you can use both approaches on the server:
InitiateAuth with AuthFlow=USER_PASSWORD_AUTH (requires app client to be created with client secret).
AdminInitiateAuth with AuthFlow=ADMIN_USER_PASSWORD_AUTH (replaced legacy ADMIN_NO_SRP_AUTH)
I believe second option makes more sense for the server usage scenario though. This way you can disable ALLOW_USER_PASSWORD_AUTH auth flow in the app client settings altogether. While probably not a huge risk, it feels cleaner to not have InitiateAuth API open to the public since it's not required.
I've built an application that is substantially a REST Web API. I would like to give to other developers the opportunity to invoke those APIs on behalf of the user. I decided to go on with OAuth authentication, basing my Authentication Service on IdentityServer3.
Right now I've succeeded in generating an Access Token for a third-party client using Authorization Flow.
What is not convincing me is how to handle my SPA that currently invokes my Web API using just cookie based authentication (+ anti-forgery token). This application in written in Javascript, based on Backbone. Substantially, what it does is just call my Web API and render results. I'm confused by the different grant flows, and I don't want to create security holes.
Solutions I've thought:
generate a token directly via Javascript. Which kind of flow should I use? How to handle token refresh?
generate a token from a backend server application and pass the generated token back to the SPA (obviously through an SSL channel). Is this somehow secure? If yes, which kind of flow should I use (I'd say Authorization Code Flow)? How to handle token refresh?
How would you handle this?
Thanks,
Marco
Here's an article that goes into an overview of which flow is right for which scenario: https://leastprivilege.com/2016/01/17/which-openid-connectoauth-2-o-flow-is-the-right-one/
I would to ask a few questions to better understand some procedures. I'm trying to write a web api project which will be a backend for both web and mobile clients.
The problem that i've in mind is about security. I don't want to use Identity or any other providers. I want to use my own database user and role structures.
Only authenticated client applications should be consuming my application. So that anonymous applications should not consume it.
So what should be the approach ? I 've written a custom AuthorizationAttribute and check some custom headers like "AppID","AppSecurity" key which i store in my own database and if the client sends the right appId and the key it means the app is authenticated to consume the API which does not sound very secure to me.
Another issue is that ; Lets say i've developed a javascript web application and i've to first authenticate the application itself before making GET/POST/PUT/DELETE etc requests which means i've to add some kind of authentication data like username, appkey, password in one of the js files for sending the "AppID" and the "AppSecurity" keys in the header. A client who knows how to use some developer tools or fiddler can easily capture my header values that are being sent to the server side? Even if i pass authentication values on the body of my json request it still can be found on the js files that are sent to the client. I'm also confused about that tooƧ
So basically i want to build a server side api that will serve the data and get data from the authenticated client applications only. What i need is a simple example for that without using any identity providers.
I'm trying to create a web application which will have a component to retrieve 3rd party data from Twitter. Assuming that I've registered my application with Twitter and have a token:
Is the preferred location to store my token on my server side code (I'm using Node / Express for my backend)? The alternative would be to store it on my client side code but that seems really dangerous since everyone would be able to inspect my code.
Assuming that I do store my token on the server side, does this mean that if I want to make AJAX calls to the 3rd party API (i.e. Twitter), the flow of the request would be from client to server, and then server to 3rd party web service?
If the above case is accurate, then would my server side code have to include some asynchronous callback / promise logic such that once the data is ready from the 3rd party web service, the server will execute my callback to send the data back to the client side?
This answer makes the assumption that you are using Twitter's "application-only authentication" to make API requests on behalf of the application itself (https://dev.twitter.com/oauth/application-only).
Your server side code is the preferred location to store any API keys you do not wish to make public. The developer guidance from Twitter states "These values should be considered as sensitive as passwords and must not be shared or distributed to untrusted parties."
Yes, using an authentication model like Twitter's "application-only authentication" would require that all third party API requests be proxied through your server side code in order to protect the API token. The same is true for any third party API that requires a simple, static API key to be passed with each request.
Although it may not technically be necessary, use of asynchronous operations on the server side when making third party API requests is preferred. This will give you a more robust architecture for dealing with the instability of internet requests as one benefit.
If you intend to read or post Twitter data on behalf of visitors to your website, be sure to read more about other methods of obtaining access tokens for use with Twitter: https://dev.twitter.com/oauth/overview. For example the "3-legged authorization" method is better suited to this scenario as it provides a secure way for the end-user to supply their Twitter credentials and authorize use of their data by the requesting application.