I want to have custom permissions for different channels for security purposes. In the documentation and examples, shortlived tokens are used. I don't want to spam the auth server every minute and don't want attackers being able to spam until their token is revoked. pubnub grants are very simple and work well. Does ably have a similar feature for access management?
According to the documentation it seems impossible:
There are also usecases where the server would want to instruct the client to re-authorize, for example to revoke some permission. There's no special mechanism for this; you can use whatever mechanism you normally use to communicate with the client to tell it to call authorize(), such as a message sent over an Ably channel that the client is listening on. If all else fails, you can wait until the token expires, at which point the client will be forced to seek a new token from your auth server. (You can specify how long the token is valid for at creation time; the default is one hour).
Source: https://support.ably.com/support/solutions/articles/3000056545-recommendations-for-incrementally-authorising-new-capabilities
I might not be understanding the question fully but Ably does have the ability to give granular permissions on a per channel level. It works by granting capabilities to an API key and scoping the API key to a channel, more info in the FAQ.
So you could:
Create an API key named Channel A Pub with only publish capabilities to channel A.
Create an API key named Channel A Sub with only subscribe capabilities to channel A.
Create an API key named Channel B Pub+Sub with both publish & subscribe capabilities to channel B.
This does require your application to use multiple API keys and create multiple Realtime/REST instances for each of them.
Creation of API keys can be done at runtime now there since the Control API has been made available. That allows for creation of apps, keys, queues, and integration rules.
In addition there is a token revocation API that can be used to revoke API keys.
Ably now has a token revocation API.
https://ably.com/docs/core-features/authentication#token-revocation
Related
Use-case:
We have a few AWSGateway APIs which our clients can use to do somethings in the backend. These APIs are Cognito protected. Currently our clients are using this APIS through an android app which was built using Cognito Mobile SDKs.
Now we are trying to expose these APIs to our clients to be integrated into their internal workflows.
I was trying to find what is the best way to do this. Currently I am not able to find any resources on how to do this.
I have seem the server side user of AWS Cognito but I don't think that is what we want to do here.
Thanks.
To answer your question correctly we need more information.
Can the internal workflows be configured to use REST Services?
What authentication processes does the internal workflows support?
SDK or no SDK
You can access the webservices in API Gateway via a generated SDK or your own code.
Instructions to generate an SDK from the API Gateway Console are found here.
To invoke the webservice with authentication can be done in four ways IAM, API Keys, Cognito, custom authoriser. I am going to mention the first three.
IAM
Step 1, create a user in IAM with an access key and secret key.
Step 2, is too setup a role to access the API using IAM. Go to
IAM, select roles, create a role, and grant it access to your
API Gateway functions. Which would look something like this:
Sample IAM Policy:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": [
"arn:aws:iam::account-id:user/Alice",
"account-id"
]
},
"Action": "execute-api:Invoke",
"Resource": [
"arn:aws:execute-api:region:account-id:api-id/stage/GET/pets"
]
}
]
}
allocate this role to the user you created. Policy examples are available here.. For more authentication options that include local certificates etc look here.
Step 3, call the API using the AWS Secret and Key SDK.
API Keys
If you add keys to your APIs the mobile app will fail as it does not have these keys. It would be best to deploy a different version of your APIs that could wrap the existing ones, could provide additional functionality specific to the workflow. To find out how to do this follow this link.
The advantage of API keys are that you can throttle access to your API Gateway functions, remove the keys at will, recycle them etc.
Cognito - Federated Users
Your mobile users are actually authenticating using federated users. However, one of the federated user channels happens to be cognito. You can add more, OpenAuth, Google, Facebook, SAML, etc, here you could add the Authentication type used by your client. A user would then use their username and password, to authenticate to the clients security provider, those credentials are then passed through to the API via federated users, and therefore federated users must be setup to use the same authentication mechanism as your client. See the following blog post
For this solution we have multiple options. 1. Pass the user credentials through to the API with federated users, this assumes the users interface calls the webservice but as you mentioned it is workflow, and I assume the user does not access the service directly as they do with the mobile application. i.e. services are called by a machine as a background process on a server. Which means this solution will not work. Option 2. is to create a new user, in cognito for the client. This is the same as accessing the service via the mobile app. To do this needs a little work extra work on the client as you need to retrieve the temporary access tokens.
Step 1. Use the SDK, or code the interface to the API on your own.
Step 2. Generate a user in Cognito for the backend system to use.
Step 3. Use the cognito user to obtain access tokens
Step 4. Use the access tokens to access the webservice in API
gateway.
Suggested solution
Create a second version of your API as a wrapper or extension to your mobile API and use API Keys as described above. Why?
Can throttle access to the APIs
A different version means you can extend it and add additional functionality specific to workflow
Easiest to implement as there is no key exchange, such updates to
the request header.
EDIT: My suggestion of solution 2 is incorrect. AWS Documentation says the following To include API methods in a usage plan, you must configure individual API methods to require an API key. For user authentication and authorization, don't use API keys. Use an IAM role, a Lambda authorizer, or an Amazon Cognito user pool.
AWS Also says the following is available for controlled access
Resource policies let you create resource-based policies to allow or deny access to your APIs and methods from specified source IP
addresses or VPC endpoints.
Standard AWS IAM roles and policies offer flexible and robust access controls that can be applied to an entire API or individual
methods.
Cross-origin resource sharing (CORS) lets you control how your API responds to cross-domain resource requests.
Lambda authorizers are Lambda functions that control access to your API methods using bearer token authentication as well as
information described by headers, paths, query strings, stage
variables, or context variables request parameters.
Amazon Cognito user pools let you create customizable authentication and authorization solutions.
Client-side SSL certificates can be used to verify that HTTP requests to your backend system are from API Gateway.
Usage plans let you provide API keys to your customers — and then track and limit usage of your API stages and methods for each API
key.
Not all the approaches above are intended for authorisation, for example CORS actually protects the user from cross site scripting, and as seen API Keys are only for usage plans. Resource policies just further secure the API by limiting access to IP Addresses, thus your only options really are IAM Roles as described in option 1, and federated users as described in option 3 or your own custom lambda authorize, if you are using Lambda, or your own authorizer if you are using something other than lambda wrapped with API Gateway.
I guess it will be service to service or (Server to Server) communication, for this terminology used is Oauth Standard is client_credentials grant type.
Please refer the documentation for getting token
Once the token is acquired, you need to pass this token either Authorization or API Gateway Custom Header for AWS Cognito.
You can use API Tokens alone for authorization (unless this has been removed recently)
I have used them on multiple applications.
This is not recommended for Authentication -- but it is application specific if they are sufficient for authorization
They have been supplemented by more secure methods at the expense of significant complication for both client and server.
API Tokens have the advantage of ease of use for issuer, client and server as they do not require complex signing or protocols -- however they are not as fundamentally secure as they may be reused and generally do not expire as quickly. Otherwise they are equivalent to bearer tokens.
Security is very context dependant -- consider these question:
what exactly are you protecting against (providing security for) ? What is the risk and cost of a security breach ? What is the cost/effort to implement and use it?
Many security 'holes' are not in the authentication protocol handling itself but rather in how data is managed 'outside the box' -- No security is perfect, meaning aiming for perfect security has unbounded cost with decreasing effectiveness. Generally, it is recommended to balance the risk and cost of potential loss vs cost to implement and maintain.
You can have a 'highly secure' API but also have a high risk of breach and data loss due to handling before and after passing through the protected gateway. There are many reasonable cases where instead of focusing on securing the 'front door' with bank vaults and armoured trucks, instead securing the data handling such that no data that is a significant security risk passes through the front door.
AWS Provides a range of technical features -- but it is ultimately up to each customer to implement them appropriate for their use. API Keys do have a range of appropriate use cases, particularly in server-to-server communications, especially where personal identity (and PI data) is not involved, or where the API involves mainly services instead of data (e.g say a image thumbnail API that stores no state and provides no access to data). When backed by use of HTTPS/SSL and possibly other security factors such as account passphrases, IP range whitelists, and a general policy of least-access.
Don't underestimate the "Sticky Note" factor. If you make secure access too painful to your users they will find a way to make it less painful, but less secure then simpler measures which they would not have had an incentive to circumvent.
I'm quite new to OpenIdConnect so excuse me if i still miss some basic concept.
I have a SPA-style web application I'm developing for my company (AspNet Core + Aurelia).
I want to use AzureAD via OpenIdConnect for authentication and authorization, everything works very well so far i'm able to obrain a token and sign in.
the problem is that my application needs to provide to the client's browser some app-specific claims like: can read X, can edit Y...
if i add these claims to the JWT token provided by AzureAD obviously it will became invalid, as the signature will not match the content.
if i generate a new token with the new claims, but signed with the app key, obviously it will be a different token valid only in the context of my app (what if I'll later need to access some other resource using the AzureAD token?, is it a good idea to insert the AzureID token as claim of the newly issued token?)
Are there something I'm missing in the OpenConnectId? or is there a way to add claims to a token issued by a 3rd-party provider like AzureAD while keeping the token valid? Maybe a way to ask AzureAd to add claims to the token and re-sign it?
I think a good way to solve this situation may be to obtain an access_token for my own application's api (from my app backend) in exchange of the id_token provided by azure (after its validation)
so the application frontend in the browser will own two tokens and it will be able to use the correct one for each type of request.
there are some standardized flow that are quite similar to this but not exactly the same.
You could try to use a custom claim mapping policy. This is documented here.
This feature is used by tenant admins to customize the claims emitted in tokens for a specific application in their tenant.
As far as I can understand, this is still in preview stage. So it may require some trial and error verification.
Alternatively, you can define some policy in your application itself. Given that you know client IDs from your application (hence you require to use them for OpenID Connect requests), you may create a simple policy to check tokens and perform verifications.
I'm looking to use API Gateway + Lambda + Cognito User Pools to build a simple REST API.
The API will be used in two ways. The first is to support a basic web app (hosted on CloudFront + S3). Authentication for the web application uses the hosted Cognito sign in / sign up flow and is working fine (with API Gateway setup to use the user pool authenticator).
The second method will be for customers to use the REST API to communicate with the system.
As an example, the client might use the web app to configure a workflow and then use an API to invoke that workflow.
What is the recommended method of authenticating the API for use with backend services?
Traditionally, I'd expect to use an API key + secret token for this purpose. I have no issue creating API keys in the API Gateway interface however I can't see anyway to link that to a specific user, nor can I see any method of specifying a secret token alongside the API key.
And assuming the above is possible, how would I set it up in such a way that I could use the JWT-based approach for the web application and the API key + secret token for customers to use.
EDIT: Additionally, I notice that app clients have an ID and a secret. Are they intended to be used for 3rd API-based-authentication (similar to how other systems make you create an app for API access)? I'm a bit skeptical because there's a limit of 25 per user pool, although it is a soft limit...
I have been searching for an answer to this myself and my searching led me to your question. I will give you my best answer from my research, assuming you want to utilize the well-known key/secret approach. Maybe others can provide a better approach.
Basically, the approach is:
Your REST API accounts are just Cognito users in a (possibly separate) user pool
The management of API accounts is done from the back end
The username and password will be the API key and secret, are administratively created (see the Admin* operations), and can be whatever format you want (within Cognito limits)
The REST API is authorized via Cognito JWT tokens
API account key and secret are only used to retrieve or refresh tokens
This requires the REST API to have a set of endpoints to support token retrieval and refresh using account keys and secrets
Based upon how long you set up the Cognito refresh interval, you can require API accounts to submit their key/secret credentials from very often to almost never
Structuring the authorization of your REST API to use Cognito tokens will allow you to integrate the REST API directly with API Gateway's support for Cognito.
I think the biggest headache of this whole thing is that you will have to create the supporting pieces for, e.g., registered users to request API accounts and for the administration of those accounts, as well as some extra helper REST endpoints for token exchange. Additionally, clients will have to keep track of keys/secrets AND token(s) as well as add client-side logic to know when to supply tokens or credentials.
When i was starting out using API gateway and Congito, i referenced https://github.com/awslabs/aws-serverless-auth-reference-app a lot and found it very helpful in demonstrating the integration between the different AWS components.
If I understand you correctly, you want to create a "long-lived API key + secret" for programmatic access to your API?
I have exactly this need, and am sadly finding that it appears to not be possible. The longest a key can be valid for is 1 hour. You can have a refresh token that's valid for 10 years. https://docs.aws.amazon.com/cognito/latest/developerguide/limits.html
I'm currently looking for an elegant solution to this. I'd be interested to hear if you ever found a solution, or if you rolled your own.
Did anyone ever find a more elegant solution to this problem?
The first answer seems like pushing too much work into the hands of my customers. I don't know the skill level of the developers calling my API, and I wouldn't wish becoming a Cognito developer on anyone lol. More seriously, I don't want them to have to store multiple pieces of information and then have to deal with refreshing tokens.
I might be Ok with giving them a refresh token. Then I could do one of two things:
Give them a refresh method. I'd figure out all the weird Cognito kinks and keep their method to a simple payload of just the refresh token. I'd give them back the access token to use on subsequent calls.
Let them pass me the refresh token as if it was an access token. I would use it on each call to get an access token and then use that to call the interior APIs.
I'm putting together a personal React site and want to send requests to an AWS API Gateway. However, I just want my site to be able to pull data. There will be no user model and every auth model I've ever used requires the user to do something with sign-in, be it user/pwd or AD. Can someone guide me to a model that covers this scenario?
One common approach is to use a Cognito Identity Pool with "Unauthenticated Identities" enabled. You can secure your API gateway endpoints using IAM, and require requests to be sig4 signed.
With this approach, Cognito is used only in a kind identity broker capacity, not as an actual identity provider. You do not need to create a User Pool or use any other identity management features of Cognito. In this capacity, Cognito is essentially just a thin layer between your code and the underlying STS APIs that produce the IAM keys your application needs.
Using the Cognito SDK, you request temporary IAM credentials (access key, secret key, session token) that can be used to sign the requests.
This answer outlines one way to accomplish this. When the protected AWS resource you want to access is API Gateway, your code may look something like the example near the end of this post.
I typically either use aws-api-gateway-client, as the example does, or aws4 with axios to sign requests.
As noted in the linked to answer above, I normally use AWS.config.credentials.get(), rather than AWS.CognitoIdentity.getCredentialsForIdentity() to actually get the IAM keys (as in this doc).
The signed requests then include an Authorization header that is very difficult to counterfeit. I don't want to suggest that this approach is bulletproof, but it does at least give you a reasonable level of confidence that your API Gateway endpoints are only being successfully invoked by your application.
Preface
I'm developing several web services and a handful of clients (web app, mobile, etc.) which will interface with said services over HTTP(s). My current work item is to design an authentication and authorization solution for the product. I have decided to leverage external identity providers, such as Facebook, Google, Microsoft, Twitter, and the like for authentication.
I'm trying to solve the problem of, "when a request comes to my server, how do I know who the user is and how can I be sure?". More questions below as well...
Requirements
Rely on external identities to indicate who I'm dealing with ('userId' essentially is all I care about).
The system should use token-based authentication (as opposed to cookies for example or basic auth).
I believe this is the right choice for scaling across multiple clients and servers while providing loose coupling.
Workflow
Based on my reading and understanding of token-based authentication, the following is how I imagine the workflow to be. Let's focus for now on Facebook in a web browser. My assumption is that other external identity providers should have similar capabilities, though I have not confirmed just yet.
Note, as of writing, I'm basing the following off of Facebook login version 2.2
Client: Initiates login to Facebook using the JavaScript SDK
Facebook: User authenticates and approves app permissions (to access user's public profile for example)
Facebook: Sends response to client which contains user’s access token, ID, and signed request
Client: Stores user access token in browser session (handled by SDK conveniently)
Client: Makes a request to my web service for a secure resource by sending along the user’s access token in the authorization header + the user’s ID (in custom header potentially)
Server: Reads user access token from request header and initiates verification by sending a request to the debug_token graph API provided by Facebook
Facebook: Responds back to the server with the user access token info (contains appId and userId)
Server: Completes verification of the token by comparing the appId to what is expected (known to itself) and the userId to what was sent on the client request
Server: Responds to the client with the requested resource (assuming the happy authorization path)
I’m imagining steps 5-9 would be repeated for subsequent requests to the server (while the user’s access token is valid – not expired, revoked from FB side, app permissions changed, etc.)
Here's a diagram to help go along with the steps. Please understand this system is not a single page application (SPA). The web services mentioned are API endpoints serving JSON data back to clients essentially; they are not serving HTML/JS/CSS (with the exception of the web client servers).
Questions
First and foremost, are there any glaring gaps / pit falls with the described approach based on my preface and requirements?
Is performing an outbound request to Facebook for verifying the access token (steps 6-8 above) per client request required / recommended?
I know at the very least, I must verify the access token coming from the client request. However, the recommended approach for subsequent verifications after the first is unknown to me. If there are typical patterns, I’m interested in hearing about them. I understand they may be application dependent based on my requirements; however, I just don’t know what to look for yet. I’ll put in the due diligence once I have a basic idea.
For instance, possible thoughts:
Hash the access token + userId pair after first verification is complete and store it in a distributed cache (accessible by all web servers) with expiry equal to access tokens. Upon subsequent requests from the clients, hash the access token + userId pair and check its existence in the cache. If present, then request is authorized. Otherwise, reach out to Facebook graph API to confirm the access token. I’m assuming this strategy might be feasible if I’m using HTTPS (which I will be). However, how does performance compare?
The accepted answer in this StackOverflow question recommends creating a custom access token after the first verification of the Facebook user token is complete. The custom token would then be sent to the client for subsequent requests. I’m wondering if this is more complex than the above solution, however. This would require implementing my own Identity Provider (something I want to avoid because I want to use external identity providers in the first place…). Is there any merit to this suggestion?
Is the signedRequest field present on the response in step #3 above (mentioned here), equivalent to the signed request parameter here in the ‘games canvas login’ flow?
They seem to be hinted as equivalent since the former links to the latter in the documentation. However, I’m surprised the verification strategy mentioned on the games page isn’t mentioned in the ‘manually building a login flow’ page of the web documentation.
If the answer to #3 is ‘Yes’, can the same identity confirmation strategy of decoding the signature and comparing to what is expected to be used on the server-side?
I’m wondering if this can be leveraged instead of making an outbound call to the debug_token graph API (step #6 above) to confirm the access token as recommended here:
Of course, in order to make the comparison on the server-side, the signed request portion would need to be sent along with the request to the server (step #5 above). In addition to feasibility without sacrificing security, I’m wondering how the performance would compare to making the outbound call.
While I’m at it, in what scenario / for what purpose, would you persist a user's access token to a database for example?
I don’t see a scenario where I would need to do this, however, I may be overlooking something. I’m curious was some common scenarios might be to spark some thoughts.
Thanks!
From what you describe I'd suggest to use a server-side login flow as described in
https://developers.facebook.com/docs/facebook-login/manually-build-a-login-flow/v2.2
so that the token is already on your server, and doesn't need to be passed from the client. If you're using non-encrypted connections, this could be a security risk (e.g. for man-in-the-middle attacks).
The steps would be:
(1) Logging people in
You need to specify the permission you want to gather from the users in the scope parameter. The request can be triggered just via a normal link:
GET https://www.facebook.com/dialog/oauth?
client_id={app-id}
&redirect_uri={redirect-uri}
&response_type=code
&scope={permission_list}
See
https://developers.facebook.com/docs/facebook-login/manually-build-a-login-flow/v2.2#login
(2) Confirm the identitity
GET https://graph.facebook.com/oauth/access_token?
client_id={app-id}
&redirect_uri={redirect-uri}
&client_secret={app-secret}
&code={code-parameter}
https://developers.facebook.com/docs/facebook-login/manually-build-a-login-flow/v2.2#confirm
(3) Inspect the access token
You can inspect the token as you already said in your question via
GET /debug_token?input_token={token-to-inspect}
&access_token={app-token-or-admin-token}
This should only be done server-side, because otherwise you'd make you app access token visible to end users (not a good idea!).
See
https://developers.facebook.com/docs/facebook-login/manually-build-a-login-flow/v2.2#checktoken
(4) Extending the access token
Once you got the (short-lived) token, you can do a call to extend the token as described in
https://developers.facebook.com/docs/facebook-login/access-tokens#extending
like the following:
GET /oauth/access_token?grant_type=fb_exchange_token
&client_id={app-id}
&client_secret={app-secret}
&fb_exchange_token={short-lived-token}
(5) Storing of access tokens
Concerning the storing of the tokens on the server, FB suggests to do so:
https://developers.facebook.com/docs/facebook-login/manually-build-a-login-flow/v2.2#token
(6) Handling expired access tokens
As FB doesn't notify you if a token has expired (and if you don't save the expiry date and compare this to the current timestamp before making a call), it's possible that you receive error messages from FB if the token got invalid (after max. 60 days). The error code will be 190:
{
"error": {
"message": "Error validating access token: Session has expired at unix
time SOME_TIME. The current unix time is SOME_TIME.",
"type": "OAuthException",
"code": 190
}
}
See
https://developers.facebook.com/docs/facebook-login/access-tokens#expiredtokens
If the access token becomes invalid, the solution is to have the person log in again, at which point you will be able to make API calls on their behalf once more. The login flow your app uses for new people should determine which method you need to adopt.
I dont' see any glaring gaps / pit falls, but I'm not a security expert.
Once your server has verified the given token (step 8), as you said:
The accepted answer in this StackOverflow question recommends creating a custom access token after the first verification of the Facebook user token is complete. The custom token would then be sent to the client for subsequent requests. I’m wondering if this is more complex than the above solution, however. This would require implementing my own Identity Provider (something I want to avoid because I want to use external identity providers in the first place…). Is there any merit to this suggestion?
IMHO is the way to go. I would use https://jwt.io/ which allows you to encode values (the userId for example) using a secret key.
Then your client attach this token to every request. So you can verify the request without need to a third party (you don't need database queries neither). The nice thing here is there is no need to store the token on your DB.
You can define an expiration date on the token, to force the client authenticate with the third party again when you want.
Let's say you want your server be able to do some action without the client interaction. For example: Open graph stories. In this scenario because you need to publish something in the name of the user you would need the access token stored on your DB.
(I can not help with the 3 and 4 questions, sorry).
Problem with Facebook is that they do not use OpenId connect on top of Oauth (https://blog.runscope.com/posts/understanding-oauth-2-and-openid-connect).
Thus resulting in their custom ways of providing Oauth authentification.
Oauth2 with OpenId connect identity services usually provide issuer endpoint where you can find URL (by appending ".well-known/openid-configuration") for jwk's which can be used to verify that JWT token and its contents were signed by the same identity service. (i.e access token originated from the same service that provided you jwk's)
For example some known openid connect identity providers:
https://accounts.google.com/.well-known/openid-configuration
https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration
(btw it is not a coincidence that Attlasian provides only these two services to perform external login)
Now as you mentioned, you need to support multiple oauth providers and since like Facebook not all providers use same configuration of oauth (they use different JWT attribute names, toke verification methods, etc. (Openid connect tries to unify this process)) i would suggest you to use some middleware identity provider like Oauth0 (service not protocol) or Keycloak. These can be used with external identity providers (Social pages as you mentioned) and also provides you with custom user store.
Advantage is that they unify authentication process under one type (e.g both support openid connect). Whereas when using multiple oauth providers with not unified authentication workflow you will end up with redudant implementations and need for merging different information's under one type (this is basically what mentioned middle-ware identity providers solve for you).
So if you will use only Facebook as identity provider in your app then go for it and make implementation directly for Facebook Oauth workflow. But with multiple identity providers (which is almost always case when creating public services) you should stick with mentioned workaround or find another one (or maybe wait till all social services will support Openid connect, which they probably wont).
There may be hope.. This year, Facebook have announced a "limited login" feature, which, if they were to add to their javascript sdks would certainly make my life easier:
https://developers.facebook.com/blog/post/2021/04/12/announcing-expanded-functionality-limited-login/
At the time of writing, I can only find reference to iOS and Unity SDKs, but it does seem to return a normal JWT, which is all I want!