AppSync: how to implement unauthenticated operations


AppSync doesn’t allow unauthenticated API calls. To allow users to call your API without first authenticating themselves, you must mimic the behaviour using one of the available authorization methods [1].

In this post, let’s look at three ways to implement unauthenticated GraphQL operations with AppSync and their pros & cons.

API Keys

To use API keys, you need to:

  1. Add an API Key in AppSync.
  2. Pass the API Key in the x-api-key header.

That’s it! It’s the easiest and most common way to implement unauthenticated GraphQL operations in AppSync.

However, AppSync API keys has a max expiry of 365 days. You can extend this by a further 365 days with the UpdateApiKey API [2]. There is no limit to how many times you can extend an API key’s expiry date.

In practice, it means you need a cron job to keep extending your API key’s expiry. It’s a manageable nuisance.

Finally, there’s no extra charge for using API keys.

Lambda authorizer

With a Lambda authorizer, the caller must provide a non-empty string in the authorization header. Instead of API keys, you can pass along a shared secret in the authorization header.

This gives you more control over the lifecycle of the shared secret (compared to using API keys).

You can also support multiple shared secrets with different levels of access. For example, different shared secrets for different clients, like this:

This is easy to implement, and you can cache authorization results for up to an hour. Furthermore, you can eliminate invalid authorization headers using the IdentityValidationExpression.

It’s a regex that allows AppSync to reject invalid authorization tokens without needing to invoke your Lambda authorizer. Of course, you won’t pay for these unauthorized requests.

However, even with caching, there will still be additional charges involved for the Lambda authorizer. There is also a performance hit because of Lambda cold starts, especially if caching means the function will not be invoked frequently.

AWS IAM

Lastly, you can use Cognito Identity Pool to issue temporary IAM credentials for unauthenticated clients. The client can then use these temporary IAM credentials to call AppSync.

Cognito Identity Pool is free to use, but the GetCredentialsForIdentity API call has a default throughput limit of 200 reqs/s.

Luckily, this is a soft limit and can be raised through the Service Quotas console or a support ticket.

Conclusions

You can enable unauthenticated GraphQL operations in AppSync through three main approaches.

  1. API Keys:east to set up and free to use, but requires periodic key renewal and offers limited control over individual clients.
  2. Lambda Authorizer (with shared secrets): offers more fine-grained access control at the expense of extra Lambda costs and potential latency from cold starts.
  3. AWS IAM via Cognito Identity Pool: leverages temporary AWS credentials for fine-grained access control. Free to use, (can be) highly scalability, though initial throughput limits and setup complexity may be a hurdle for simple use cases.

Here is a side-by-side comparison of their pros and cons:

Links

[1] Configuring authorization and authentication to secure your GraphQL APIs

[2] UpdateApiKey API

Master Serverless

Join 17K readers and level up you AWS game with just 5 mins a week.

Read more from Master Serverless

A common challenge when building APIs is supporting multiple live versions without letting the system turn into an unmaintainable mess. You need to keep older versions running for existing clients, roll out new versions safely, and avoid breaking changes that might take down production. And you need to do all that without duplicating too much infrastructure or introducing spaghetti logic inside your code. There’s no official pattern for versioning APIs in API Gateway + Lambda. API Gateway...

I recently shared six event versioning strategies for event-driven architectures [1]. In response to this, Marty Pitt reached out and showed me how Orbital [2] and Taxi [3] use semantic tags to eliminate schema coupling in event-driven architectures and simplify the schema management. It's a novel way to manage schema evolution, and I want to share what I learnt with you. Problems with Schema Coupling In an event-driven architecture, event consumers are typically coupled to the schema of the...

Last week, we looked at 6 ways to version event schemas [1] and found the best solution is to avoid breaking changes and minimise the need for versioning. But how exactly do you do that? How can you prevent accidental breaking changes from creeping in? You can detect and stop breaking changes: At runtime, when the events are ingested; During development, when schema changes are made; Or a combination of both! Here are three approaches you should consider. 1. Consumer-Driven Contracts In...