Amplify has re-imagined the way frontend developers build fullstack applications. Develop and deploy without the hassle.

Page updated Apr 29, 2024

Define authorization rules

When determining the authorization mode for your REST endpoint, there are a few built in options and customizations you can do.

IAM Authorization

By default, the API will be using IAM authorization and the requests will be signed for you automatically. IAM authorization has two modes: one using an unauthenticated role, and one using an authenticated role. When the user has not signed in through Amplify.Auth.signIn, the unauthenticated role is used by default. Once the user has signed in, the authenticate role is used, instead.

When you created your REST API with the Amplify CLI, you were asked if you wanted to restrict access. If you selected no, then the unauthenticated role will have access to the API. If you selected yes, you would have configured more fine grain access to your API.

Unauthenticated Requests

You can use the API category to access API Gateway endpoints that don't require authentication. In this case, you need to allow unauthenticated identities in your Amazon Cognito Identity Pool settings. For more information, please visit Amazon Cognito Developer Documentation.

When your API is configured to use IAM as the authorization type, your requests will automatically have IAM credentials added to the headers of outgoing requests. You can verify that IAM is being used as the authorization type by inspecting the authorizationType associated with your API in amplifyconfiguration.json:

{
"awsAPIPlugin": {
"[YOUR-RESTENDPOINT-NAME]": {
"endpointType": "REST",
"endpoint": "YOUR-REST-ENDPOINT",
"region": "us-west-2",
"authorizationType": "AWS_IAM"
}
}
}

API Key

If you want to configure a public REST API, you can set an API key in Amazon API Gateway. Then, update your amplifyconfiguration.json to reference it. The value associated to the "authorizationType" key should be "API_KEY". Also include a "apiKey" as a key, and set its value to whatever you configured in API Gateway.

{
"awsAPIPlugin": {
"[YOUR-RESTENDPOINT-NAME]": {
"endpointType": "REST",
"endpoint": "YOUR-REST-ENDPOINT",
"region": "us-west-2",
"authorizationType": "API_KEY",
"apiKey": "YOUR_API_KEY"
}
}
}

Cognito User pool authorization

If you set up the API Gateway with a custom authorization with a Cognito User pool, then you can set the amplifyconfiguration.json to use AMAZON_COGNITO_USER_POOLS .

{
"awsAPIPlugin": {
"[YOUR-RESTENDPOINT-NAME]": {
"endpointType": "REST",
"endpoint": "YOUR-REST-ENDPOINT",
"region": "us-west-2",
"authorizationType": "AMAZON_COGNITO_USER_POOLS"
}
}
}

Your amplifyconfiguration.json should contain Cognito configuration in the awsCognitoAuthPlugin block, including details about your Cognito user pool:

{
"CognitoUserPool": {
"Default": {
"PoolId": "YOUR-POOL-ID",
"AppClientId": "YOUR-APP-CLIENT-ID",
"AppClientSecret": "YOUR-APP-CLIENT-SECRET",
"Region": "us-east-1"
}
},
"CredentialsProvider": {
"CognitoIdentity": {
"Default": {
"PoolId": "YOUR-COGNITO-IDENTITY-POOLID",
"Region": "us-east-1"
}
}
}
}

With this configuration, your access token will automatically be included in outbound requests to your API, as an Authorization header. For more details on how to configure the API Gateway with the custom authorization, see this

OIDC

If you are using a 3rd party OIDC provider you will need to configure it and manage the details of token refreshes yourself. Update the amplifyconfiguration.json file and code snippet as follows:

{
...
"awsAPIPlugin": {
"[YOUR-RESTENDPOINT-NAME]": {
"endpointType": "REST",
"endpoint": "[REST-ENDPOINT]",
"region": "[REGION]",
"authorizationType": "OPENID_CONNECT",
}
}
}

Add the following code to your app:

ApiAuthProviders authProviders = ApiAuthProviders.builder()
.oidcAuthProvider(() -> "[OPEN-ID-CONNECT-TOKEN]")
.build();
AWSApiPlugin plugin = AWSApiPlugin.builder()
.apiAuthProviders(authProviders)
.build();
Amplify.addPlugin(plugin);
val authProviders = ApiAuthProviders.builder()
.oidcAuthProvider { "[OPEN-ID-CONNECT-TOKEN]" }
.build()
val plugin = AWSApiPlugin.builder()
.apiAuthProviders(authProviders)
.build()
Amplify.addPlugin(plugin)

The Access Token contains scopes and groups and is used to grant access to authorized resources. This is a tutorial for enabling custom scopes..

The ID Token contains claims about the identity of the authenticated user such as name, email, and phone_number. It could have custom claims as well, for example using Amplify CLI.

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, set the authorization type to OPENID_CONNECT and use Amplify.Auth to retrieve the ID Token for your requests.

Add the following code to your app to initialize API plugin with OIDC auth provider:

This implementation uses CompletableFuture<T>, which requires minSdkVersion >= 24.

ApiAuthProviders authProviders = ApiAuthProviders.builder()
.oidcAuthProvider(() -> {
CompletableFuture<String> future = new CompletableFuture<>();
Amplify.Auth.fetchAuthSession(
session -> future.complete(((AWSCognitoAuthSession) session)
.getUserPoolTokens()
.getValue()
.getIdToken()),
future::completeExceptionally
);
try {
return future.get();
} catch (Exception e) {
e.printStackTrace();
}
return null;
})
.build();
AWSApiPlugin plugin = AWSApiPlugin.builder()
.apiAuthProviders(authProviders)
.build();
Amplify.addPlugin(plugin);

This implementation uses CompletableFuture<T>, which requires minSdkVersion >= 24.

val authProviders = ApiAuthProviders.builder()
.oidcAuthProvider {
val future = CompletableFuture<String>()
Amplify.Auth.fetchAuthSession(
{ future.complete((it as AWSCognitoAuthSession).userPoolTokens.value?.idToken) },
{ future.completeExceptionally(it) }
)
future.get()
}
.build()
val plugin = AWSApiPlugin.builder()
.apiAuthProviders(authProviders)
.build()
Amplify.addPlugin(plugin)

This implementation uses CompletableFuture<T>, which requires minSdkVersion >= 24.

val authProviders = ApiAuthProviders.builder()
.oidcAuthProvider {
val session = runBlocking { Amplify.Auth.fetchAuthSession() }
return (session as AWSCognitoAuthSession).userPoolTokens.value?.idToken
}
.build()
val plugin = AWSApiPlugin.builder()
.apiAuthProviders(authProviders)
.build()
Amplify.addPlugin(plugin)

Using the rxbindings module can simplify this further.

dependencies {
// other dependencies...
implementation 'com.amplifyframework:rxbindings:ANDROID_VERSION'
}
ApiAuthProviders authProviders = ApiAuthProviders.builder()
.oidcAuthProvider(() -> RxAmplify.Auth.fetchAuthSession()
.map(session -> ((AWSCognitoAuthSession) session)
.getUserPoolTokens()
.getValue()
.getIdToken())
.blockingGet())
.build();
AWSApiPlugin plugin = AWSApiPlugin.builder()
.apiAuthProviders(authProviders)
.build();
Amplify.addPlugin(plugin);

Using the rxbindings module can simplify this further.

dependencies {
// other dependencies...
implementation 'com.amplifyframework:rxbindings:ANDROID_VERSION'
}
val authProviders = ApiAuthProviders.builder()
.oidcAuthProvider { RxAmplify.Auth.fetchAuthSession()
.map { (it as AWSCognitoAuthSession)
.userPoolTokens
.value
?.idToken }
.blockingGet() }
.build()
val plugin = AWSApiPlugin.builder()
.apiAuthProviders(authProviders)
.build()
Amplify.addPlugin(plugin)

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": {
"[yourApiName]": {
"endpointType": "REST",
"endpoint": "[REST-ENDPOINT]",
"region": "[REGION]",
"authorizationType": "NONE",
}
}
}

If you would like to add request headers, you can add it directly to the request

This implementation uses CompletableFuture<T>, which requires minSdkVersion >= 24.

RestOptions options = RestOptions.builder()
.addHeaders(Collections.singletonMap("key", "value"))
.build();

This implementation uses CompletableFuture<T>, which requires minSdkVersion >= 24.

val options = RestOptions.builder()
.addHeaders(mapOf("key" to "value"))
.build()

This implementation uses CompletableFuture<T>, which requires minSdkVersion >= 24.

val request = RestOptions.builder()
.addHeaders(mapOf("key" to "value"))
.build()
RestOptions options = RestOptions.builder()
.addHeaders(Collections.singletonMap("key", "value"))
.build();

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 specify your own headers, use the configureClient() configuration option on the AWSApiPlugin's builder. Specify the name of one of the configured APIs in your amplifyconfiguration.json. Apply customizations to the underlying OkHttp instance by providing a lambda expression as below.

AWSApiPlugin plugin = AWSApiPlugin.builder()
.configureClient("yourApiName", okHttpBuilder -> {
okHttpBuilder.addInterceptor(chain -> {
Request originalRequest = chain.request();
Request updatedRequest = originalRequest.newBuilder()
.addHeader("customHeader", "someValue")
.build();
return chain.proceed(updatedRequest);
});
})
.build();
Amplify.addPlugin(plugin);
val plugin = AWSApiPlugin.builder()
.configureClient("yourApiName") { okHttpBuilder ->
okHttpBuilder.addInterceptor { chain ->
val originalRequest = chain.request()
val updatedRequest = originalRequest.newBuilder()
.addHeader("customHeader", "someValue")
.build()
chain.proceed(updatedRequest)
}
}
.build()
Amplify.addPlugin(plugin)
val plugin = AWSApiPlugin.builder()
.configureClient("yourApiName") { okHttpBuilder ->
okHttpBuilder.addInterceptor { chain ->
val originalRequest = chain.request()
val updatedRequest = originalRequest.newBuilder()
.addHeader("customHeader", "someValue")
.build()
chain.proceed(updatedRequest)
}
}
.build()
Amplify.addPlugin(plugin)
AWSApiPlugin plugin = AWSApiPlugin.builder()
.configureClient("yourApiName", okHttpBuilder -> {
okHttpBuilder.addInterceptor(chain -> {
Request originalRequest = chain.request();
Request updatedRequest = originalRequest.newBuilder()
.addHeader("customHeader", "someValue")
.build();
return chain.proceed(updatedRequest);
});
})
.build();
RxAmplify.addPlugin(plugin);

Customizing HTTP request headers

To use custom headers on your HTTP request, you need to add these to Amazon API Gateway first. For more info about configuring headers, please visit Amazon API Gateway Developer Guide

If you used the Amplify CLI to create your API, you can enable custom headers by following these steps:

  1. Visit Amazon API Gateway console.
  2. On Amazon API Gateway console, click on the path you want to configure (e.g. /{proxy+})
  3. Then click the Actions dropdown menu and select Enable CORS
  4. Add your custom header (e.g. my-custom-header) on the text field Access-Control-Allow-Headers, separated by commas, like: 'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token,my-custom-header'.
  5. Click on 'Enable CORS and replace existing CORS headers' and confirm.
  6. Finally, similar to step 3, click the Actions drop-down menu and then select Deploy API. Select Development on deployment stage and then Deploy. (Deployment could take a couple of minutes).