Page updated Nov 9, 2023

Configure authorization modes

For client authorization AppSync supports API Keys, Amazon IAM credentials, Amazon Cognito User Pools, and 3rd party OIDC providers. This is inferred from the amplifyconfiguration.json/.dart file when you call Amplify.configure(). You can configure auth modes for an API using the Amplify CLI or manual configuration.

Auth Modes

API key

API Key is the easiest way to setup and prototype your application with AWS AppSync. This means it is also prone to abuse since anyone can easily discover the API Key and make requests to your public service. To have authorization checks, use the other auth modes such as Cognito user pool or AWS IAM. API Key will expiry according to the expiry time set when provisioning AWS AppSync and will require extending it or creating a new one if needed. Default API Key expiry time is 7 days.

Amazon Cognito User Pools

Amazon Cognito User Pools is most commonly used with AWS AppSync when adding authorization check on your API calls. If your application needs to interact with other AWS services besides AWS AppSync, such as Amazon S3, you will need to use AWS IAM credentials with Amazon Cognito Identity Pools. Amplify CLI can automatically configure this for you and will also automatically use the authenticated user from User Pools to federate with the Identity Pools to provide the AWS IAM credentials in the application. See this for more information about the differences. This allows you to have both User Pools' credentials for AWS AppSync and AWS IAM credentials for other AWS resources. You can learn more about Amplify Auth outlined in the Accessing credentials section.

IAM

Amazon Cognito Identity Pools allows you to use credentials from AWS IAM in your app. AWS IAM helps you securely control access to AWS resources. You use IAM to control who is authenticated (signed in) and authorized (has permissions) to use AWS resources. Learn more about IAM . The Amplify CLI can automatically configure this for you.

OpenID Connect (OIDC)

If you are using a 3rd party OIDC provider you will need to configure it and manage the details of token refreshes yourself.

AWS Lambda

You can implement your own custom API authorization logic using an AWS Lambda function. To add a Lambda function as an authorization mode for your AppSync API, go to the Settings section of the AppSync console.

You will need to manage the details of token refreshes in your application code yourself.

Use Amplify CLI to configure authorization modes

Amplify CLI can automatically configure the auth modes for you when running amplify add api or amplify update api if you want to change the auth mode.

If you already have auth configured, then you need to run amplify update api to use this pre-configured auth mode and CLI will not ask for auth settings again.

amplify update api
1amplify update api
? Please select from one of the below mentioned services: > `GraphQL` ? Select a setting to edit: > `Authorization modes` ? Choose the default authorization type for the API API key Amazon Cognito User Pool ❯ IAM OpenID Connect
1? Please select from one of the below mentioned services:
2 > `GraphQL`
3? Select a setting to edit:
4 > `Authorization modes`
5? Choose the default authorization type for the API
6 API key
7 Amazon Cognito User Pool
8❯ IAM
9 OpenID Connect

Manual Configuration

API Key

Add the following snippet to your amplifyconfiguration.json/.dart file, under the awsAPIPlugin:

{ ... "awsAPIPlugin": { "[YOUR-GRAPHQLENDPOINT-NAME]": { "endpointType": "GraphQL", "endpoint": "[GRAPHQL-ENDPOINT]", "region": "[REGION]", "authorizationType": "API_KEY", "apiKey": "[API-KEY]" } } }
1{
2 ...
3 "awsAPIPlugin": {
4 "[YOUR-GRAPHQLENDPOINT-NAME]": {
5 "endpointType": "GraphQL",
6 "endpoint": "[GRAPHQL-ENDPOINT]",
7 "region": "[REGION]",
8 "authorizationType": "API_KEY",
9 "apiKey": "[API-KEY]"
10 }
11 }
12}

Amazon Cognito User Pools

Add the following snippet to your amplifyconfiguration.json/.dart file, under the awsCognitoAuthPlugin:

{ ... "awsCognitoAuthPlugin": { "CognitoUserPool": { "Default": { "PoolId": "[POOL-ID]", "AppClientId": "[APP-CLIENT-ID]", "Region": "[REGION]" } } } }
1{
2 ...
3 "awsCognitoAuthPlugin": {
4 "CognitoUserPool": {
5 "Default": {
6 "PoolId": "[POOL-ID]",
7 "AppClientId": "[APP-CLIENT-ID]",
8 "Region": "[REGION]"
9 }
10 }
11 }
12}

and under the awsAPIPlugin

{ ... "awsAPIPlugin": { "[YOUR-GRAPHQLENDPOINT-NAME]": { "endpointType": "GraphQL", "endpoint": "[GRAPHQL-ENDPOINT]", "region": "[REGION]", "authorizationType": "AMAZON_COGNITO_USER_POOLS", } } }
1{
2 ...
3 "awsAPIPlugin": {
4 "[YOUR-GRAPHQLENDPOINT-NAME]": {
5 "endpointType": "GraphQL",
6 "endpoint": "[GRAPHQL-ENDPOINT]",
7 "region": "[REGION]",
8 "authorizationType": "AMAZON_COGNITO_USER_POOLS",
9 }
10 }
11}

Add the following code to your app:

func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? ) -> Bool { try! Amplify.add(plugin: AWSCognitoAuthPlugin()) try! Amplify.add(plugin: AWSAPIPlugin()) try! Amplify.configure() print("Amplify initialized") return true }
1func application(
2 _ application: UIApplication,
3 didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
4 ) -> Bool {
5 try! Amplify.add(plugin: AWSCognitoAuthPlugin())
6 try! Amplify.add(plugin: AWSAPIPlugin())
7 try! Amplify.configure()
8 print("Amplify initialized")
9
10 return true
11 }

IAM

Add the following snippet to your amplifyconfiguration.json/.dart file:

{ ... "awsCognitoAuthPlugin": { "CredentialsProvider": { "CognitoIdentity": { "Default": { "PoolId": "[COGNITO-IDENTITY-POOLID]", "Region": "[REGION]" } } } } }
1{
2 ...
3 "awsCognitoAuthPlugin": {
4 "CredentialsProvider": {
5 "CognitoIdentity": {
6 "Default": {
7 "PoolId": "[COGNITO-IDENTITY-POOLID]",
8 "Region": "[REGION]"
9 }
10 }
11 }
12 }
13}

and under the awsAPIPlugin

{ ... "awsAPIPlugin": { "[YOUR-GRAPHQLENDPOINT-NAME]": { "endpointType": "GraphQL", "endpoint": "[GRAPHQL-ENDPOINT]", "region": "[REGION]", "authorizationType": "AWS_IAM", } } }
1{
2 ...
3 "awsAPIPlugin": {
4 "[YOUR-GRAPHQLENDPOINT-NAME]": {
5 "endpointType": "GraphQL",
6 "endpoint": "[GRAPHQL-ENDPOINT]",
7 "region": "[REGION]",
8 "authorizationType": "AWS_IAM",
9 }
10 }
11}

OIDC

Update the amplifyconfiguration.json/.dart file and code snippet as follows:

{ ... "awsAPIPlugin": { "[YOUR-GRAPHQLENDPOINT-NAME]": { "endpointType": "GraphQL", "endpoint": "[GRAPHQL-ENDPOINT]", "region": "[REGION]", "authorizationType": "OPENID_CONNECT", } } }
1{
2 ...
3 "awsAPIPlugin": {
4 "[YOUR-GRAPHQLENDPOINT-NAME]": {
5 "endpointType": "GraphQL",
6 "endpoint": "[GRAPHQL-ENDPOINT]",
7 "region": "[REGION]",
8 "authorizationType": "OPENID_CONNECT",
9 }
10 }
11}

Add the following code to your app:

  • Create a subclass of APIAuthProviderFactory
class MyAPIAuthProviderFactory: APIAuthProviderFactory { let myAuthProvider = MyOIDCAuthProvider() override func oidcAuthProvider() -> AmplifyOIDCAuthProvider? { return myAuthProvider } }
1class MyAPIAuthProviderFactory: APIAuthProviderFactory {
2 let myAuthProvider = MyOIDCAuthProvider()
3
4 override func oidcAuthProvider() -> AmplifyOIDCAuthProvider? {
5 return myAuthProvider
6 }
7}
  • Implement your class which conforms to AmplifyOIDCAuthProvider:
class MyOIDCAuthProvider : AmplifyOIDCAuthProvider { func getLatestAuthToken() async throws -> String { .... } }
1class MyOIDCAuthProvider : AmplifyOIDCAuthProvider {
2 func getLatestAuthToken() async throws -> String {
3 ....
4 }
5}
  • Finally, register your instance of APIAuthProviderFactory prior to calling Amplify.configure():
try Amplify.add(plugin: AWSAPIPlugin(apiAuthProviderFactory: MyAPIAuthProviderFactory())) try Amplify.configure()
1try Amplify.add(plugin: AWSAPIPlugin(apiAuthProviderFactory: MyAPIAuthProviderFactory()))
2try Amplify.configure()

If you are using Cognito's user pool as the authorization type, this will by default retrieve and use the Access Token for your requests. If you would like to override this behavior and use the ID Token instead, you can treat Cognito user pool as your OIDC provider and use Amplify.Auth to retrieve the ID Token for your requests.

import AWSPluginsCore class MyOIDCAuthProvider : AmplifyOIDCAuthProvider { func getLatestAuthToken() async throws -> String { let session = try await Amplify.Auth.fetchAuthSession() if let cognitoTokenResult = (session as? AuthCognitoTokensProvider)?.getCognitoTokens() { switch cognitoTokenResult { case .success(let tokens): return tokens.idToken case .failure(let error): throw error } } throw AuthError.unknown("Could not retrieve Cognito token") } }
1import AWSPluginsCore
2
3class MyOIDCAuthProvider : AmplifyOIDCAuthProvider {
4 func getLatestAuthToken() async throws -> String {
5 let session = try await Amplify.Auth.fetchAuthSession()
6 if let cognitoTokenResult = (session as? AuthCognitoTokensProvider)?.getCognitoTokens() {
7 switch cognitoTokenResult {
8 case .success(let tokens):
9 return tokens.idToken
10 case .failure(let error):
11 throw error
12 }
13 }
14
15 throw AuthError.unknown("Could not retrieve Cognito token")
16 }
17}

AWS Lambda

Amplify CLI does not currently allow you to configure Lambda as an authorization mode for your GraphQL API. To add a Lambda function as an authorization mode for your AppSync API, go to the Settings section of the AppSync console. Then, update the authorizationType value in the amplifyconfiguration.json/.dart file and code snippet as follows:

{ ... "awsAPIPlugin": { "[YOUR-GRAPHQLENDPOINT-NAME]": { "endpointType": "GraphQL", "endpoint": "[GRAPHQL-ENDPOINT]", "region": "[REGION]", "authorizationType": "AWS_LAMBDA", } } }
1{
2 ...
3 "awsAPIPlugin": {
4 "[YOUR-GRAPHQLENDPOINT-NAME]": {
5 "endpointType": "GraphQL",
6 "endpoint": "[GRAPHQL-ENDPOINT]",
7 "region": "[REGION]",
8 "authorizationType": "AWS_LAMBDA",
9 }
10 }
11}

Add the following code to your app:

  • Create a subclass of APIAuthProviderFactory
class MyAPIAuthProviderFactory: APIAuthProviderFactory { let myAuthProvider = MyFunctionAuthProvider() override func functionAuthProvider() -> AmplifyFunctionAuthProvider? { return MyFunctionAuthProvider() } }
1class MyAPIAuthProviderFactory: APIAuthProviderFactory {
2 let myAuthProvider = MyFunctionAuthProvider()
3
4 override func functionAuthProvider() -> AmplifyFunctionAuthProvider? {
5 return MyFunctionAuthProvider()
6 }
7}
  • Implement your class which conforms to AmplifyFunctionAuthProvider:
class MyFunctionAuthProvider : AmplifyFunctionAuthProvider { func getLatestAuthToken() async throws -> String { .... } }
1class MyFunctionAuthProvider : AmplifyFunctionAuthProvider {
2 func getLatestAuthToken() async throws -> String {
3 ....
4 }
5}
  • Finally, register your instance of APIAuthProviderFactory prior to calling Amplify.configure():
try Amplify.add(plugin: AWSAPIPlugin(apiAuthProviderFactory: MyAPIAuthProviderFactory())) try Amplify.configure()
1try Amplify.add(plugin: AWSAPIPlugin(apiAuthProviderFactory: MyAPIAuthProviderFactory()))
2try Amplify.configure()

NONE

You can also set authorization mode to NONE so that the library will not provide any request interception logic. You can use this when your API does not require any authorization or when you want to manipulate the request yourself, such as adding header values or authorization data.

{ ... "awsAPIPlugin": { "[YOUR-GRAPHQLENDPOINT-NAME]": { "endpointType": "GraphQL", "endpoint": "[GRAPHQL-ENDPOINT]", "region": "[REGION]", "authorizationType": "NONE", } } }
1{
2 ...
3 "awsAPIPlugin": {
4 "[YOUR-GRAPHQLENDPOINT-NAME]": {
5 "endpointType": "GraphQL",
6 "endpoint": "[GRAPHQL-ENDPOINT]",
7 "region": "[REGION]",
8 "authorizationType": "NONE",
9 }
10 }
11}

You can register your own request interceptor to intercept the request and perform an action or inject something into your request before it is performed.

To include custom headers in your outgoing requests, add an URLRequestInterceptor to the AWSAPIPlugin. Also specify the name of one of the APIs configured in your amplifyconfiguration.json file.

struct CustomInterceptor: URLRequestInterceptor { func intercept(_ request: URLRequest) throws -> URLRequest { var request = request request.setValue("headerValue", forHTTPHeaderField: "headerKey") return request } } let apiPlugin = try AWSAPIPlugin() try Amplify.addPlugin(apiPlugin) try Amplify.configure() try apiPlugin.add(interceptor: CustomInterceptor(), for: "yourApiName")
1struct CustomInterceptor: URLRequestInterceptor {
2 func intercept(_ request: URLRequest) throws -> URLRequest {
3 var request = request
4 request.setValue("headerValue", forHTTPHeaderField: "headerKey")
5 return request
6 }
7}
8let apiPlugin = try AWSAPIPlugin()
9try Amplify.addPlugin(apiPlugin)
10try Amplify.configure()
11try apiPlugin.add(interceptor: CustomInterceptor(), for: "yourApiName")

Configure multiple authorization modes

There is currently a known issue where enabling multi-auth modes for the API plugin may break DataStore functionality if the DataStore plugin is also used in the same App.

If you are planning to enable multi-auth for only the DataStore plugin, please refer to the configure multiple authorization types section in DataStore documentation.

If you are planning to enable multi-auth for both the API and DataStore plugins, please monitor the aforementioned issue for the latest progress and updates.

This section talks about the capability of AWS AppSync to configure multiple authorization modes for a single AWS AppSync endpoint and region. Follow the AWS AppSync Multi-Auth to configure multiple authorization modes for your AWS AppSync endpoint.

You can now configure a single GraphQL API to deliver private and public data. Private data requires authenticated access using authorization mechanisms such as IAM, Cognito User Pools, and OIDC. Public data does not require authenticated access and is delivered through authorization mechanisms such as API Keys. You can also configure a single GraphQL API to deliver private data using more than one authorization type. For example, you can configure your GraphQL API to authorize some schema fields using OIDC, while other schema fields through Cognito User Pools and/or IAM.

As discussed in the above linked documentation, certain fields may be protected by different authorization types. This can lead the same query, mutation, or subscription to have different responses based on the authorization sent with the request; Therefore, it is recommended to use the different friendly_name_<AuthMode> as the apiName parameter in the Amplify.API call to reference each authorization type.

The following snippets highlight the new values in the amplifyconfiguration.json/.dart and the client code configurations.

The friendly_name illustrated here is created from Amplify CLI prompt. There are 4 clients in this configuration that connect to the same API except that they use different AuthMode.

{ "UserAgent": "aws-amplify-cli/2.0", "Version": "1.0", "api": { "plugins": { "awsAPIPlugin": { "[FRIENDLY-NAME-API-WITH-API-KEY]": { "endpointType": "GraphQL", "endpoint": "[GRAPHQL-ENDPOINT]", "region": "[REGION]", "authorizationType": "API_KEY", "apiKey": "[API_KEY]" }, "[FRIENDLY-NAME-API-WITH-IAM]": { "endpointType": "GraphQL", "endpoint": "[GRAPHQL-ENDPOINT]", "region": "[REGION]", "authorizationType": "AWS_IAM" }, "[FRIENDLY-NAME-API-WITH-USER-POOLS]": { "endpointType": "GraphQL", "endpoint": "https://xyz.appsync-api.us-west-2.amazonaws.com/graphql", "region": "[REGION]", "authorizationType": "AMAZON_COGNITO_USER_POOLS" }, "[FRIENDLY-NAME-API-WITH-OPENID-CONNECT]": { "endpointType": "GraphQL", "endpoint": "https://xyz.appsync-api.us-west-2.amazonaws.com/graphql", "region": "[REGION]", "authorizationType": "OPENID_CONNECT" } } } } }
1{
2 "UserAgent": "aws-amplify-cli/2.0",
3 "Version": "1.0",
4 "api": {
5 "plugins": {
6 "awsAPIPlugin": {
7 "[FRIENDLY-NAME-API-WITH-API-KEY]": {
8 "endpointType": "GraphQL",
9 "endpoint": "[GRAPHQL-ENDPOINT]",
10 "region": "[REGION]",
11 "authorizationType": "API_KEY",
12 "apiKey": "[API_KEY]"
13 },
14 "[FRIENDLY-NAME-API-WITH-IAM]": {
15 "endpointType": "GraphQL",
16 "endpoint": "[GRAPHQL-ENDPOINT]",
17 "region": "[REGION]",
18 "authorizationType": "AWS_IAM"
19 },
20 "[FRIENDLY-NAME-API-WITH-USER-POOLS]": {
21 "endpointType": "GraphQL",
22 "endpoint": "https://xyz.appsync-api.us-west-2.amazonaws.com/graphql",
23 "region": "[REGION]",
24 "authorizationType": "AMAZON_COGNITO_USER_POOLS"
25 },
26 "[FRIENDLY-NAME-API-WITH-OPENID-CONNECT]": {
27 "endpointType": "GraphQL",
28 "endpoint": "https://xyz.appsync-api.us-west-2.amazonaws.com/graphql",
29 "region": "[REGION]",
30 "authorizationType": "OPENID_CONNECT"
31 }
32 }
33 }
34 }
35}

The GRAPHQL-ENDPOINT from AWS AppSync will look similar to https://xyz.appsync-api.us-west-2.amazonaws.com/graphql.

When you have configured multiple APIs, you can specify the name of the API as a parameter as the target for an operation:

let request = GraphQLRequest(apiName: "[FRIENDLY-NAME-API-WITH-API-KEY]", ...) try await Amplify.API.mutate(request: request)
1let request = GraphQLRequest(apiName: "[FRIENDLY-NAME-API-WITH-API-KEY]", ...)
2try await Amplify.API.mutate(request: request)