Several years ago, I worked for a company that issued RFID security badges to its employees. Every morning I’d find a parking spot, walk to a metal turnstile in the fence, and wave my badge in front of a black, plastic box. I would hear a metallic click and a light on the box would turn green. Then I knew I could push my way through the turnstile and walk toward my office building, which had its own black box next to the door.
This story illustrates two fundamental concepts in security: authentication and authorization. I’ll quickly explain the difference between the two and introduce a few authentication methods available for your serverless backend.
What’s the Difference Between Authentication and Authorization?
Authentication is the process of verifying that the person making the request is who they say they are. In the story above, my badge was how I authenticated myself to the turnstile. It had a number encoded in it that said, This is Ben. Another example would be showing your photo ID when you go through security at the airport.
When I waved my badge in front of the black box, the system was able to verify who I was—that’s authentication. Once it knew who I was, it needed to determine if I had authorization—or permission—to open the door. Once it decided that I had permission to enter, it made the light on the box turn green and unlocked the turnstile because I was authorized to enter.
Options for Adding Auth to a Serverless API
You can use one of AWS’s built-in authentication methods in your API Gateway or AppSync APIs. Or if you need some extra features, there are plenty of third-party services, some of which you can self-host.
IAM
Identity and Access Management, or IAM, is AWS’s authentication system. It’s used for authentication and authorization for management tasks, like the AWS Console, CLI, or calling from one resource to another.
Cognito
Cognito provides AWS’s native user pool solution. You can authenticate users through a standard username/password flow or sign in with a social authentication provider. If you need some more security, it handles multi-factor authentication. Also, AWS provides some React libraries so you can easily integrate it into your web app.
Third-party Auth Providers
If you want to wander outside of AWS’s provided services, you have a few options for authentication. Auth0 is the most well-known, but there are others like Okta, One Login, and FusionAuth.
Roll Your Own
If you have a unique authentication method or, like a lot of developers, the guilty pleasure of reinventing the wheel, you can make your own authentication service. The simplest way would be to create a user database, a CRUD API, and an endpoint to generate JWT tokens.
API Keys
An honorable mention, API keys provide the least specific form of authentication. It’s a bit like the combination for a lock. Anyone that you give that number to has access. Anyone they give the number to will have access as well.
A Deeper Dive into Your Options
Let’s try for a bit more insight into each of those options, now that you’ve got a broad overview.
AWS IAM
AWS IAM is how AWS controls access to resources natively. When you log in to the AWS console or use the CLI, your request is authorized by IAM.
How Does It Work?
You can use IAM to control access to an API Gateway or AppSync API by attaching a role to the resource that’s making requests. At runtime, the resource will assume the role, which will allow it to make requests to your API depending on what permissions you’ve given to the role.
For example, if you create a Lambda that needs access to your AppSync API, you would first define a role that provides that permission and allows the Lambda service to assume the role. When your Lambda starts, it will tell IAM that it wants to assume the role that you defined. IAM will authenticate the request by verifying that it came from a Lambda and that Lambdas are allowed to assume the role. Once the Lambda has been authenticated, IAM will provide the lambda with temporary credentials to use when making requests to AWS services.
When your Lambda makes a request to your AppSync API, it will send the credentials it got from IAM along with its request to AppSync. AppSync will verify that the credentials have permission to carry out the requested action. If the credentials have permission, then AppSync will carry out the request and return the result.
Any Drawbacks or Limitations?
While you can use Cognito Identity Pools to exchange a social login token for an IAM role, IAM authentication is only for AWS users to access and manage resources.
How Is Pricing Handled?
IAM is a free service, so use it as much as you want. Seriously, use IAM to secure your resources.
AWS Cognito
AWS Cognito is the default choice when you want to enable user login for your serverless application. It gives a lot of functionality out of the box, like password resets, multi-factor authentication, social account linking, user groups, and more.
How Does It Work?
Users authenticate with a username and password. Once the user pool has authenticated the user, it will send back a token. Then, when a user makes a request to your API Gateway, it will attach the token to it. API Gateway will validate the token automatically, check that the authenticated user has authorization to perform the request, and finally return the response.
sequenceDiagram participant App as Mobile App participant UserPool as Cognito User Pool participant API as API Gateway App->>UserPool: Send username and password UserPool->>App: Issue JWT token App->>API: Send request with JWT token API<<->>UserPool: Validate JWT token API-->>API: Check Authorization API->>App: Response
What Are Identity Pools?
When you open Cognito in the AWS Console, you have two options:
- User pools
- Identity pools
So far, we’ve only been talking about user pools. So, what are identity pools?
Identity pools provide a service called identity federation. Identity federation allows you to offload authentication to another service. The client authenticates the user with a service like Apple, Facebook, or Google. Once the user is authenticated, they get a token from the service and give it to an identity pool.
The identity pool will then verify the token came from a valid authentication service. Once it’s satisfied that the token is valid, it will return temporary AWS credentials that use an IAM role that you’ve attached to the identity pool.
How Is Pricing Handled?
User pool pricing is based on the number of users that interact with the service in a given month. AWS refers to this as Monthly Active Users or MAU. It doesn’t matter if the user does a token refresh, or signs in ten times, they only count as one active user.
The table below shows how much you’ll pay for a specific number of users, but this is just to give a general idea of cost. For the most accurate information, see the Cognito pricing page.
MAU | Total Price |
---|---|
50k | $0 |
100k | $275 |
1 million | $4,415 |
10 million | $33,665 |
Third-party JWT Auth Providers
Cognito has fantastic integration with other AWS services, but it does have an ugly side. The most frustrating issue that I’ve found is there are a lot of user pool properties that cannot be changed once the pool is created.
I worked on a web app with a Cognito user pool that was created before case-insensitive usernames were the default—maybe before it was an option. Unfortunately, I didn’t realize that was the case until users were already signed up, so I couldn’t change the property. This oversight resulted in a lot of changes in the codebase to enforce lowercase usernames.
How Do They Work?
Most third-party providers will have the same basic features as a Cognito user pool, plus some extras. The user will sign in using OAuth 2, then get a token back. When you receive one of these tokens on the backend, you’ll need to validate it, something that cognito takes care of automatically.
Drawbacks
Each provider has its list of pros and cons. In general, the drawbacks of using a third-party provider over cognito are billing and developer convenience.
Most third-party auth providers require you to pay someone besides AWS, so your billing is split to another company. With Cognito, you can tag each user pool with your environment (development, testing, production, etc.) and group environment resources together on a billing report.
Another advantage of user pools is they can be defined in a CloudFormation stack—without having to create custom resources. While you can’t change a lot about a user pool after creation, it is easier to build it in the first place if it’s in a CloudFormation template.
Finally, as I mentioned before, AWS automatically handles user pool token validation. If you’re using a third-party provider, you’ll have to manually validate the token against it’s signature.