

# Custom authentication and authorization


 AWS IoT Core lets you define custom authorizers so that you can manage your own client authentication and authorization. This is useful when you need to use authentication mechanisms other than the ones that AWS IoT Core natively supports. (For more information about the natively supported mechanisms, see [Client authentication](client-authentication.md)).  

 For example, if you are migrating existing devices in the field to AWS IoT Core and these devices use a custom bearer token or MQTT user name and password to authenticate, you can migrate them to AWS IoT Core without having to provision new identities for them. You can use custom authentication with any of the communication protocols that AWS IoT Core supports. For more information about the protocols that AWS IoT Core supports, see [Device communication protocols](protocols.md). 

**Topics**
+ [

# Understanding the custom authentication workflow
](custom-authorizer.md)
+ [

# Creating and managing custom authorizers (CLI)
](config-custom-auth.md)
+ [

# Custom authentication with X.509 client certificates
](custom-auth-509cert.md)
+ [

# Connecting to AWS IoT Core by using custom authentication
](custom-auth.md)
+ [

# Troubleshooting your authorizers
](custom-auth-troubleshooting.md)

# Understanding the custom authentication workflow


Custom authentication enables you to define how to authenticate and authorize clients by using [authorizer resources](https://docs.aws.amazon.com/iot/latest/apireference/API_AuthorizerDescription.html).  Each authorizer contains a reference to a customer-managed Lambda function, an optional public key for validating device credentials, and additional configuration information. The following diagram illustrates the authorization workflow for custom authentication in AWS IoT Core.

![\[Custom authorization workflow for custom authentication in AWS IoT Core.\]](http://docs.aws.amazon.com/iot/latest/developerguide/images/custom-authentication.png)


## AWS IoT Core custom authentication and authorization workflow


The following list explains each step in the custom authentication and authorization workflow.

1. A device connects to a customer’s AWS IoT Core data endpoint by using one of the supported [Device communication protocols](protocols.md). The device passes credentials in either the request’s header fields or query parameters (for the HTTP Publish or MQTT over WebSockets protocols), or in the user name and password field of the MQTT CONNECT message (for the MQTT and MQTT over WebSockets protocols).

1. AWS IoT Core checks for one of two conditions:
   + The incoming request specifies an authorizer.
   + The AWS IoT Core data endpoint receiving the request has a default authorizer configured for it.

   If AWS IoT Core finds an authorizer in either of these ways, AWS IoT Core triggers the Lambda function associated with the authorizer.

1.  (Optional) If you've enabled token signing, AWS IoT Core validates the request signature by using the public key stored in the authorizer before triggering the Lambda function. If validation fails, AWS IoT Core stops the request without invoking the Lambda function.  

1. The Lambda function receives the credentials and connection metadata in the request and makes an authentication decision.

1. The Lambda function returns the results of the authentication decision and an AWS IoT Core policy document that specifies what actions are allowed in the connection. The Lambda function also returns information that specifies how often AWS IoT Core revalidates the credentials in the request by invoking the Lambda function.

1. AWS IoT Core evaluates activity on the connection against the policy it has received from the Lambda function.

1. After the connection is established and your custom authorizer Lambda is initially invoked, the next invocation can be delayed for up to 5 minutes on idle connections without any MQTT operations. After that, subsequent invocations will follow the refresh interval in your custom authorizer Lambda. This approach can prevent excessive invocations that could exceed the Lambda concurrency limit of your AWS account.

## Scaling considerations


 Because a Lambda function handles authentication and authorization for your authorizer, the function is subject to Lambda pricing and service limits, such as concurrent execution rate. For more information about Lambda pricing, see [Lambda Pricing](https://aws.amazon.com/lambda/pricing/). You can manage the load on your Lambda function by adjusting the `refreshAfterInSeconds` and `disconnectAfterInSeconds` parameters in your Lambda function response. For more information about the contents of your Lambda function response, see [Defining your Lambda function](custom-auth-lambda.md).

**Note**  
If you leave signing enabled, you can prevent excessive triggering of your Lambda by unrecognized clients. Consider this before you disable signing in your authorizer.

**Note**  
The Lambda function timeout limit for custom authorizer is 5 seconds.

# Creating and managing custom authorizers (CLI)


AWS IoT Core implements custom authentication and authorization schemes by using custom authorizers. A custom authorizer is an AWS IoT Core resource that gives you the flexibility to define and implement the rules and policies based on your specific requirements. To create a custom authorizer with step-by-step instructions, see [Tutorial: Creating a custom authorizer for AWS IoT Core](https://docs.aws.amazon.com//iot/latest/developerguide/custom-auth-tutorial.html).

Each authorizer consists of the following components: 
+  *Name*: A unique user-defined string that identifies the authorizer.
+  *Lambda function ARN*: The Amazon Resource Name (ARN) of the Lambda function that implements the authorization and authentication logic.  
+  *Token key name*: The key name used to extract the token from the HTTP headers, query parameters, or MQTT CONNECT user name in order to perform signature validation. This value is required if signing is enabled in your authorizer. 
+  *Signing disabled flag (optional)*: A Boolean value that specifies whether to disable the signing requirement on credentials. This is useful for scenarios where signing the credentials doesn't make sense, such as authentication schemes that use MQTT user name and password. The default value is `false`, so signing is enabled by default. 
+  *Token signing public key*: The public key that AWS IoT Core uses to validate the token signature. Its minimum length is 2,048 bits. This value is required if signing is enabled in your authorizer.  

Lambda charges you for the number of times your Lambda function runs and for the amount of time it takes for the code in your function to execute. For more information about Lambda pricing, see [Lambda Pricing](https://aws.amazon.com/lambda/pricing/). For more information about creating Lambda functions, see the [Lambda Developer Guide](https://docs.aws.amazon.com/lambda/latest/dg/).

**Note**  
If you leave signing enabled, you can prevent excessive triggering of your Lambda by unrecognized clients. Consider this before you disable signing in your authorizer.

**Note**  
The Lambda function timeout limit for custom authorizer is 5 seconds.

**Topics**
+ [

# Defining your Lambda function
](custom-auth-lambda.md)
+ [

# Creating an authorizer
](custom-auth-create-authorizer.md)
+ [

# Authorizing AWS IoT to invoke your Lambda function
](custom-auth-authorize.md)
+ [

# Testing your authorizers
](custom-auth-testing.md)
+ [

# Managing custom authorizers
](custom-auth-manage.md)

# Defining your Lambda function


 When AWS IoT Core invokes your authorizer, it triggers the associated Lambda associated with the authorizer with an event that contains the following JSON object. The example JSON object contains all of the possible fields. Any fields that aren't relevant to the connection request aren't included.

```
{
    "token" :"aToken",
    "signatureVerified": Boolean, // Indicates whether the device gateway has validated the signature.
    "protocols": ["tls", "http", "mqtt"], // Indicates which protocols to expect for the request.
    "protocolData": {
        "tls" : {
            "serverName": "serverName" // The server name indication (SNI) host_name string.
        },
        "http": {
            "headers": {
                "#{name}": "#{value}"
            },
            "queryString": "?#{name}=#{value}"
        },
        "mqtt": {
            "username": "myUserName",
            "password": "myPassword", // A base64-encoded string.
            "clientId": "myClientId" // Included in the event only when the device sends the value.
        }
    },
    "connectionMetadata": {
        "id": UUID // The connection ID. You can use this for logging.
    },
}
```

 The Lambda function should use this information to authenticate the incoming connection and decide what actions are permitted in the connection. The function should send a response that contains the following values. 
+  `isAuthenticated`: A Boolean value that indicates whether the request is authenticated.
+  `principalId`: An alphanumeric string that acts as an identifier for the token sent by the custom authorization request. The value must be an alphanumeric string with at least one, and no more than 128, characters and match this regular expression (regex) pattern: `([a-zA-Z0-9]){1,128}`. Special characters that are not alphanumeric are not allowed for use with the `principalId` in AWS IoT Core. Refer to the documentation for other AWS services if non-alphanumeric special characters are allowed for the `principalId`.
+  `policyDocuments`: A list of JSON-formatted AWS IoT Core policy documents For more information about creating AWS IoT Core policies, see [AWS IoT Core policies](iot-policies.md). The maximum number of policy documents is 10 policy documents. Each policy document can contain a maximum of 2,048 characters.
+  `disconnectAfterInSeconds`: An integer that specifies the maximum duration (in seconds) of the connection to the AWS IoT Core gateway. The minimum value is 300 seconds, and the maximum value is 86,400 seconds. The default value is 86,400.
**Note**  
The value of `disconnectAfterInSeconds` (returned by the Lambda function) is set when the connection establishes. This value cannot be modified during subsequent policy refresh Lambda invocations.
+  `refreshAfterInSeconds`: An integer that specifies the interval between policy refreshes. When this interval passes, AWS IoT Core invokes the Lambda function to allow for policy refreshes. The minimum value is 300 seconds, and the maximum value is 86,400 seconds. 

  The following JSON object contains an example of a response that your Lambda function can send. 

 **\$1 "isAuthenticated":true, //A Boolean that determines whether client can connect. "principalId": "xxxxxxxx",  //A string that identifies the connection in logs. "disconnectAfterInSeconds": 86400,  "refreshAfterInSeconds": 300,   "policyDocuments": [       \$1         "Version": "2012-10-17",         "Statement": [            \$1               "Action": "iot:Publish",               "Effect": "Allow",               "Resource": "arn:aws:iot:us-east-1:<your\$1aws\$1account\$1id>:topic/customauthtesting"             \$1          ]        \$1     ] \$1**

 The `policyDocument` value must contain a valid AWS IoT Core policy document. For more information about AWS IoT Core policies, see [AWS IoT Core policies](iot-policies.md).  In MQTT over TLS and MQTT over WebSockets connections, AWS IoT Core caches this policy for the interval specified in the value of the `refreshAfterInSeconds` field. In the case of HTTP connections the Lambda function is called for every authorization request unless your device is using HTTP persistent connections (also called HTTP keep-alive or HTTP connection reuse) you can choose to enable caching when configuring the authorizer. During this interval, AWS IoT Core authorizes actions in an established connection against this cached policy without triggering your Lambda function again. If failures occur during custom authentication, AWS IoT Core terminates the connection. AWS IoT Core also terminates the connection if it has been open for longer than the value specified in the `disconnectAfterInSeconds`parameter. 

 The following JavaScript contains a sample Node.js Lambda function that looks for a password in the MQTT Connect message with a value of `test` and returns a policy that grants permission to connect to AWS IoT Core with a client named `myClientName` and publish to a topic that contains the same client name. If it doesn't find the expected password, it returns a policy that denies those two actions. 

```
// A simple Lambda function for an authorizer. It demonstrates 
// how to parse an MQTT password and generate a response.

exports.handler = function(event, context, callback) { 
    var uname = event.protocolData.mqtt.username;
    var pwd = event.protocolData.mqtt.password;
    var buff = new Buffer(pwd, 'base64');
    var passwd = buff.toString('ascii');
    switch (passwd) { 
        case 'test': 
            callback(null, generateAuthResponse(passwd, 'Allow')); 
            break;
        default: 
            callback(null, generateAuthResponse(passwd, 'Deny'));  
    }
};

// Helper function to generate the authorization response.
var generateAuthResponse = function(token, effect) { 
    var authResponse = {}; 
    authResponse.isAuthenticated = true; 
    authResponse.principalId = 'TEST123'; 
    
    var policyDocument = {}; 
    policyDocument.Version = '2012-10-17';		 	 	 
    policyDocument.Statement = []; 
    var publishStatement = {}; 
    var connectStatement = {};
    connectStatement.Action = ["iot:Connect"];
    connectStatement.Effect = effect;
    connectStatement.Resource = ["arn:aws:iot:us-east-1:123456789012:client/myClientName"];
    publishStatement.Action = ["iot:Publish"]; 
    publishStatement.Effect = effect; 
    publishStatement.Resource = ["arn:aws:iot:us-east-1:123456789012:topic/telemetry/myClientName"]; 
    policyDocument.Statement[0] = connectStatement;
    policyDocument.Statement[1] = publishStatement; 
    authResponse.policyDocuments = [policyDocument]; 
    authResponse.disconnectAfterInSeconds = 3600; 
    authResponse.refreshAfterInSeconds = 300;
    
    return authResponse; 
}
```

 The preceding Lambda function returns the following JSON when it receives the expected password of `test` in the MQTT Connect message. The values of the `password` and `principalId` properties will be the values from the MQTT Connect message.

```
{
  "password": "password",
  "isAuthenticated": true,
  "principalId": "principalId",
  "policyDocuments": [
    {
      "Version": "2012-10-17",		 	 	 
      "Statement": [
        {
          "Action": "iot:Connect",
          "Effect": "Allow",
          "Resource": "*"
        },
        {
          "Action": "iot:Publish",
          "Effect": "Allow",
          "Resource": "arn:aws:iot:region:accountId:topic/telemetry/${iot:ClientId}"
        },
        {
          "Action": "iot:Subscribe",
          "Effect": "Allow",
          "Resource": "arn:aws:iot:region:accountId:topicfilter/telemetry/${iot:ClientId}"
        },
        {
          "Action": "iot:Receive",
          "Effect": "Allow",
          "Resource": "arn:aws:iot:region:accountId:topic/telemetry/${iot:ClientId}"
        }
      ]
    }
  ],
  "disconnectAfterInSeconds": 3600,
  "refreshAfterInSeconds": 300
}
```

# Creating an authorizer


 You can create an authorizer by using the [CreateAuthorizer API](https://docs.aws.amazon.com/iot/latest/apireference/API_CreateAuthorizer.html). The following example describes the command. 

```
aws iot create-authorizer
--authorizer-name MyAuthorizer
--authorizer-function-arn arn:aws:lambda:us-west-2:<account_id>:function:MyAuthorizerFunction  //The ARN of the Lambda function.
[--token-key-name MyAuthorizerToken //The key used to extract the token from headers.
[--token-signing-public-keys FirstKey=
 "-----BEGIN PUBLIC KEY-----
  [...insert your public key here...] 
  -----END PUBLIC KEY-----"
[--status ACTIVE]
[--tags <value>]
[--signing-disabled | --no-signing-disabled]
```

You can use the `signing-disabled` parameter to opt out of signature validation for each invocation of your authorizer. We strongly recommend that you do not disable signing unless you have to. Signature validation protects you against excessive invocations of your Lambda function from unknown devices. You can't update the `signing-disabled` status of an authorizer after you create it. To change this behavior, you must create another custom authorizer with a different value for the `signing-disabled` parameter. 

Values for the `tokenKeyName` and `tokenSigningPublicKeys` parameters are optional if you have disabled signing. They are required values if signing is enabled. 

After you create your Lambda function and the custom authorizer, you must explicitly grant the AWS IoT Core service permission to invoke the function on your behalf. You can do this with the following command. 

**Note**  
The default IoT endpoint might not support using custom authorizers with Lambda functions. Instead, you can use domain configurations to define a new endpoint and then specify that endpoint for the custom authorizer.

```
aws lambda add-permission --function-name <lambda_function_name>
--principal iot.amazonaws.com --source-arn <authorizer_arn>
--statement-id Id-123 --action "lambda:InvokeFunction"
```

# Authorizing AWS IoT to invoke your Lambda function


In this section, you'll grant the permission of the custom authorizer resource that you just created to run the Lambda function. To grant the permission, you can use the [add-permission](https://docs.aws.amazon.com//cli/latest/reference/lambda/add-permission.html) CLI command.

**Grant permission to your Lambda function using the AWS CLI**

1. After inserting your values, enter the following command. Note that the `statement-id` value must be unique. Replace `Id-1234` with the exact value you have, otherwise, you might get a `ResourceConflictException` error.

   ```
   aws lambda add-permission  \
   --function-name "custom-auth-function" \
   --principal "iot.amazonaws.com" \
   --action "lambda:InvokeFunction" \
   --statement-id "Id-1234" \
   --source-arn authorizerArn
   ```

1. If the command succeeds, it returns a permission statement, such as this example. You can continue to the next section to test the custom authorizer.

   ```
   {
       "Statement": "{\"Sid\":\"Id-1234\",\"Effect\":\"Allow\",\"Principal\":{\"Service\":\"iot.amazonaws.com\"},\"Action\":\"lambda:InvokeFunction\",\"Resource\":\"arn:aws:lambda:Region:57EXAMPLE833:function:custom-auth-function\",\"Condition\":{\"ArnLike\":{\"AWS:SourceArn\":\"arn:aws:lambda:Region:57EXAMPLE833:function:custom-auth-function\"}}}"
   }
   ```

   If the command doesn't succeed, it returns an error, such as this example. You'll need to review and correct the error before you continue.

   ```
   An error occurred (AccessDeniedException) when calling the AddPermission operation: User: arn:aws:iam::57EXAMPLE833:user/EXAMPLE-1 is not authorized to perform: lambda:AddPer
   mission on resource: arn:aws:lambda:Region:57EXAMPLE833:function:custom-auth-function
   ```

# Testing your authorizers


 You can use the [TestInvokeAuthorizer](https://docs.aws.amazon.com/iot/latest/apireference/API_TestInvokeAuthorizer.html) API to test the invocation and return values of your authorizer. This API enables you to specify protocol metadata and test the signature validation in your authorizer.

The following tabs show how to use the AWS CLI to test your authorizer.

------
#### [ Unix-like ]

```
aws iot test-invoke-authorizer --authorizer-name NAME_OF_AUTHORIZER \
--token TOKEN_VALUE --token-signature TOKEN_SIGNATURE
```

------
#### [ Windows CMD ]

```
aws iot test-invoke-authorizer --authorizer-name NAME_OF_AUTHORIZER ^
--token TOKEN_VALUE --token-signature TOKEN_SIGNATURE
```

------
#### [ Windows PowerShell ]

```
aws iot test-invoke-authorizer --authorizer-name NAME_OF_AUTHORIZER `
--token TOKEN_VALUE --token-signature TOKEN_SIGNATURE
```

------

The value of the `token-signature` parameter is the signed token. To learn how to obtain this value, see [Signing the token](custom-auth.md#custom-auth-token-signature).

If your authorizer takes a user name and password, you can pass this information by using the `--mqtt-context` parameter. The following tabs show how to use the `TestInvokeAuthorizer` API to send a JSON object that contains a user name, password, and client name to your custom authorizer.

------
#### [ Unix-like ]

```
aws iot test-invoke-authorizer --authorizer-name NAME_OF_AUTHORIZER  \
--mqtt-context '{"username": "USER_NAME", "password": "dGVzdA==", "clientId":"CLIENT_NAME"}'
```

------
#### [ Windows CMD ]

```
aws iot test-invoke-authorizer --authorizer-name NAME_OF_AUTHORIZER  ^
--mqtt-context '{"username": "USER_NAME", "password": "dGVzdA==", "clientId":"CLIENT_NAME"}'
```

------
#### [ Windows PowerShell ]

```
aws iot test-invoke-authorizer --authorizer-name NAME_OF_AUTHORIZER  `
--mqtt-context '{"username": "USER_NAME", "password": "dGVzdA==", "clientId":"CLIENT_NAME"}'
```

------

The password must be base64-encoded. The following example shows how to encode a password in a Unix-like environment.

```
echo -n PASSWORD | base64
```

# Managing custom authorizers


 You can manage your authorizers by using the following APIs. 
+ [ListAuthorizers](https://docs.aws.amazon.com/iot/latest/apireference/API_ListAuthorizers.html): Show all authorizers in your account.
+  [DescribeAuthorizer](https://docs.aws.amazon.com/iot/latest/apireference/API_DescribeAuthorizer.html): Displays properties of the specified authorizer. These values include creation date, last modified date, and other attributes.
+ [SetDefaultAuthorizer](https://docs.aws.amazon.com/iot/latest/apireference/API_SetDefaultAuthorizer.html): Specifies the default authorizer for your AWS IoT Core data endpoints. AWS IoT Core uses this authorizer if a device doesn't pass AWS IoT Core credentials and doesn't specify an authorizer. For more information about using AWS IoT Core credentials, see [Client authentication](client-authentication.md).
+ [UpdateAuthorizer](https://docs.aws.amazon.com/iot/latest/apireference/API_UpdateAuthorizer.html):  Changes the status, token key name, or public keys for the specified authorizer.
+  [DeleteAuthorizer](https://docs.aws.amazon.com/iot/latest/apireference/API_DeleteAuthorizer.html): Deletes the specified authorizer. 

**Note**  
 You can't update an authorizer's signing requirement. This means that you can't disable signing in an existing authorizer that requires it. You also can't require signing in an existing authorizer that doesn't require it. 

# Custom authentication with X.509 client certificates


When connecting devices to AWS IoT Core, you have multiple [authentication types](protocols.md#connection-protocol-auth-mode) available. You can use [X.509 client certificates](https://docs.aws.amazon.com//iot/latest/developerguide/x509-client-certs.html) that can be used to authenticate client and device connections, or define [custom authorizers](https://docs.aws.amazon.com//iot/latest/developerguide/custom-authentication.html) to manage your own client authentication and authorization logic. This topic covers how to use custom authentication with X.509 client certificates.

Using custom authentication with X.509 certificates can be helpful if you've already authenticated your devices using X.509 certificates and want to perform additional validation and custom authorization. For example, if you store your devices' data such as their serial numbers in the X.509 client certificate, after AWS IoT Core authenticated the X.509 client certificate, you can use a custom authorizer to identify specific devices based on the information stored in the certificate's CommonName field. Using custom authentication with X.509 certificates can enhance your device security management when connecting devices to AWS IoT Core and provides more flexibility to manage the authentication and authorization logic. AWS IoT Core supports custom authentication with X.509 certificates using the X.509 certificate and custom authorizer authentication type, which works with both the [MQTT](https://docs.aws.amazon.com//iot/latest/developerguide/mqtt.html) protocol and the [HTTPS](https://docs.aws.amazon.com//iot/latest/developerguide/http.html) protocol. For more information about the authentication types and application protocols that AWS IoT Core device endpoints support, see [Device communication protocols](https://docs.aws.amazon.com//iot/latest/developerguide/protocols.html).

**Note**  
Custom authentication with X.509 client certificates is not supported in the AWS GovCloud (US) Regions.

**Important**  
You must use an endpoint created using [domain configurations](iot-custom-endpoints-configurable.md). In addition, clients must provide the [Server Name Indication (SNI)](https://www.rfc-editor.org/rfc/rfc3546#section-3.1) extension when connecting to AWS IoT Core.

**Topics**
+ [

## Step 1: Register your X.509 client certificates with AWS IoT Core
](#custom-auth-509cert-client)
+ [

## Step 2: Create a Lambda function
](#custom-auth-509cert-lambda)
+ [

## Step 3: Create a custom authorizer
](#custom-auth-509cert-authorizer)
+ [

## Step 4: Set authentication type and application protocol in a domain configuration
](#custom-auth-509cert-domainconfig)

## Step 1: Register your X.509 client certificates with AWS IoT Core


If you haven't done this already, register and activate your [X.509 client certificates](https://docs.aws.amazon.com//iot/latest/developerguide/x509-client-certs.html) with AWS IoT Core. Otherwise, skip to the next step.

To register and activate your client certificates with AWS IoT Core, follow the steps:

1. If you [create client certificates directly with AWS IoT](https://docs.aws.amazon.com//iot/latest/developerguide/device-certs-create.html). These client certificates will be automatically registered with AWS IoT Core.

1. If you [create your own client certificates](https://docs.aws.amazon.com//iot/latest/developerguide/device-certs-your-own.html), follow [these instructions to register them with AWS IoT Core](https://docs.aws.amazon.com//iot/latest/developerguide/register-device-cert.html).

1. To activate your client certificates, follow [these instructions](https://docs.aws.amazon.com//iot/latest/developerguide/activate-or-deactivate-device-cert.html).

## Step 2: Create a Lambda function


AWS IoT Core uses custom authorizers to implement custom authentication and authorization schemes. A custom authorizer is associated with a Lambda function that determines whether a device is authenticated and what operations the device is allowed to perform. When a device connects to AWS IoT Core, AWS IoT Core retrieves the authorizer details including authorizer name and associated Lambda function, and invokes the Lambda function. The Lambda function receives an event that contains a JSON object with the device's X.509 client certificate data. Your Lambda function uses this event JSON object to evaluate the authentication request, decide the actions to take, and send a response back.

### Lambda function event example


The following example JSON object contains all possible fields that can be included. The actual JSON object will only contain fields relevant to the specific connection request.

```
{
	"token": "aToken",
	"signatureVerified": true,
	"protocols": [
		"tls",
		"mqtt"
	],
	"protocolData": {
		"tls": {
			"serverName": "serverName",
			"x509CertificatePem": "x509CertificatePem",
			"principalId": "principalId"
		},
		"mqtt": {
			"clientId": "myClientId",
                     "username": "myUserName",
                     "password": "myPassword"
		}
	},
	"connectionMetadata": {
		"id": "UUID"
	}
}
```

`signatureVerified`  
A Boolean value that indicates whether the token signature configured in the authorizer is verified or not before invoking the authorizer's Lambda function. If the authorizer is configured to disable token signing, this field will be false. 

`protocols`  
An array that contains the protocols to expect for the request.

`protocolData`  
An object that contains information of the protocols used in the connection. It provides protocol-specific details that can be useful for authentication, authorization, and more.  
`tls` - This object holds information related to the TLS (Transport Layer Security) protocol.   
+ `serverName` - The [Server Name Indication (SNI)](https://www.rfc-editor.org/rfc/rfc3546#section-3.1) hostname string. AWS IoT Core requires devices to send the [SNI extension](https://www.rfc-editor.org/rfc/rfc3546#section-3.1) to the Transport Layer Security (TLS) protocol and provide the complete endpoint address in the `host_name` field.
+ `x509CertificatePem` - The X.509 certificate in PEM format, which is used for client authentication in the TLS connection.
+ `principalId` - The principal identifier associated with the client in the TLS connection.
`mqtt` - This object holds information related to the MQTT protocol.  
+ `clientId` - A string only needs to be included in the event that the device sends this value.
+ `username` - The user name provided in the MQTT Connect packet.
+ `password` - The password provided in the MQTT Connect packet.

`connectionMetadata`  
Metadata of the connection.  
`id` - The connection ID, which you can use for logging and troubleshooting.

**Note**  
In this event JSON object, `x509CertificatePem` and `principalId` are two new fields in the request. The value of `principalId` is the same as the value of `certificateId`. For more information, see [Certificate](https://docs.aws.amazon.com//iot/latest/apireference/API_Certificate.html).

### Lambda function response example


The Lambda function should use information from the event JSON object to authenticate the incoming connection and decide what actions are permitted in the connection.

The following JSON object contains an example response that your Lambda function can send.

```
{
	"isAuthenticated": true,
	"principalId": "xxxxxxxx",
	"disconnectAfterInSeconds": 86400,
	"refreshAfterInSeconds": 300,
	"policyDocuments": [
		{
			"Version": "2012-10-17",		 	 	 
			"Statement": [
				{
					"Effect": "Allow",
					"Action": "iot:Publish",
					"Resource": "arn:aws:iot:us-east-1:123456789012:topic/customauthtesting"
				}
			]
		}
	]
}
```

In this example, this function should send a response that contains the following values.

`isAuthenticated`  
A Boolean value that indicates whether the request is authenticated.

`principalId`  
An alphanumeric string that acts as an identifier for the token sent by the custom authorization request. The value must be an alphanumeric string with at least one, and no more than 128, characters. It identifies the connection in logs. The value of `principalId` must be the same as the value of `principalId` in the event JSON object (i.e. certificateId of the X.509 certificate).

`policyDocuments`  
A list of JSON-formatted AWS IoT Core policy documents. The value is optional and supports [thing policy variables](https://docs.aws.amazon.com//iot/latest/developerguide/thing-policy-variables.html) and [certificate policy variables](https://docs.aws.amazon.com//iot/latest/developerguide/cert-policy-variables.html). The maximum number of policy documents is 10. Each policy document can contain a maximum of 2,048 characters. If you have multiple policies attached to your client certificate and the Lambda function, the permission is a collection of all policies. For more information about creating AWS IoT Core policies, see [Policies](https://docs.aws.amazon.com//iot/latest/developerguide/iot-policies.html).

`disconnectAfterInSeconds`  
An integer that specifies the maximum duration (in seconds) of the connection to the AWS IoT Core gateway. The minimum value is 300 seconds, and the maximum value is 86,400 seconds. `disconnectAfterInSeconds` is for the lifetime of a connection and doesn't get refreshed on consecutive policy refreshes.

`refreshAfterInSeconds`  
An integer that specifies the interval between policy refreshes. When this interval passes, AWS IoT Core invokes the Lambda function to allow for policy refreshes. The minimum value is 300 seconds, and the maximum value is 86,400 seconds.

### Example Lambda function


The following is a sample Node.js Lambda function. The function examines the client's X.509 certificate and extracts relevant information such as the serial number, fingerprint, and subject name. If the extracted information matches the expected values, the client is granted access to connect. This mechanism ensures that only authorized clients with valid certificates can establish a connection.

```
const crypto = require('crypto');

exports.handler = async (event) => {
    
    // Extract the certificate PEM from the event
    const certPem = event.protocolData.tls.x509CertificatePem;
    
    // Parse the certificate using Node's crypto module
    const cert = new crypto.X509Certificate(certPem);
    
    var effect = "Deny";
    // Allow permissions only for a particular certificate serial, fingerprint, and subject
    if (cert.serialNumber === "7F8D2E4B9C1A5036DE8F7C4B2A91E5D80463BC9A1257" // This is a random serial
       && cert.fingerprint === "F2:9A:C4:1D:B5:E7:08:3F:6B:D0:4E:92:A7:C1:5B:8D:16:0F:E3:7A" // This is a random fingerprint
       && cert.subject === "allow.example.com") {
      effect = "Allow";
    }
    
    return generateAuthResponse(event.protocolData.tls.principalId, effect);
};


// Helper function to generate the authorization response.
function generateAuthResponse(principalId, effect) {
    const authResponse = {
        isAuthenticated: true,
        principalId,
        disconnectAfterInSeconds: 3600,
        refreshAfterInSeconds: 300,
        policyDocuments: [
          {
            Version: "2012-10-17",		 	 	 
            Statement: [
              {
                Action: ["iot:Connect"],
                Effect: effect,
                Resource: [
                  "arn:aws:iot:us-east-1:123456789012:client/myClientName"
                ]
              },
              {
                Action: ["iot:Publish"],
                Effect: effect,
                Resource: [
                  "arn:aws:iot:us-east-1:123456789012:topic/telemetry/myClientName"
                ]
              },
              {
                Action: ["iot:Subscribe"],
                Effect: effect,
                Resource: [
                   "arn:aws:iot:us-east-1:123456789012:topicfilter/telemetry/myClientName"
                ]
              },
              {
                Action: ["iot:Receive"],
                Effect: effect,
                Resource: [
                   "arn:aws:iot:us-east-1:123456789012:topic/telemetry/myClientName"
                ]
              }
            ]
          }
        ]
      };

  return authResponse;
}
```

The preceding Lambda function returns the following JSON when it receives a certificate with the expected serial, fingerprint, and subject. The value of `x509CertificatePem` will be the client certificate provided in the TLS handshake. For more information, see [Defining your Lambda function](https://docs.aws.amazon.com//iot/latest/developerguide/config-custom-auth.html#custom-auth-lambda).

```
{
	"isAuthenticated": true,
	"principalId": "principalId in the event JSON object",
	"policyDocuments": [
		{
			"Version": "2012-10-17",		 	 	 
			"Statement": [
				{
					"Action": "iot:Connect",
					"Effect": "Allow",
					"Resource": "arn:aws:iot:us-east-1:123456789012:client/myClientName"
				},
				{
					"Action": "iot:Publish",
					"Effect": "Allow",
					"Resource": "arn:aws:iot:us-east-1:123456789012:topic/telemetry/myClientName"
				},
				{
					"Action": "iot:Subscribe",
					"Effect": "Allow",
					"Resource": "arn:aws:iot:us-east-1:123456789012:topicfilter/telemetry/myClientName"
				},
				{
					"Action": "iot:Receive",
					"Effect": "Allow",
					"Resource": "arn:aws:iot:us-east-1:123456789012:topic/telemetry/myClientName"
				}
			]
		}
	],
	"disconnectAfterInSeconds": 3600,
	"refreshAfterInSeconds": 300
}
```

## Step 3: Create a custom authorizer


After [you define the Lambda function](#custom-auth-509cert-lambda), create a custom authorizer to manage your own client authentication and authorization logic. You can follow the detailed instructions in [Step 3: Create a customer authorizer resource and its authorization](https://docs.aws.amazon.com//iot/latest/developerguide/custom-auth-tutorial.html#custom-auth-tutorial-authorizer). For more information, see [Creating an authorizer](https://docs.aws.amazon.com//iot/latest/developerguide/config-custom-auth.html). 

In the process of creating the custom authorizer, you must grant AWS IoT permission to invoke the Lambda function after it's created. For detailed instructions, see [Authorizing AWS IoT to invoke your Lambda function](custom-auth-authorize.md).

## Step 4: Set authentication type and application protocol in a domain configuration


To authenticate devices using custom authentication with X.509 client certificates, you must set the authentication type and application protocol in a domain configuration, and you must send the SNI extension. The value of `authenticationType` must be `CUSTOM_AUTH_X509`, and the value of `applicationProtocol` can either be `SECURE_MQTT` or `HTTPS`.

### Set authentication type and application protocol in domain configuration (CLI)


If you don't have a domain configuration, use the [https://docs.aws.amazon.com//cli/latest/reference/iot/create-domain-configuration.html](https://docs.aws.amazon.com//cli/latest/reference/iot/create-domain-configuration.html) command to create one. The value of `authenticationType` must be `CUSTOM_AUTH_X509`, and the value of `applicationProtocol` can either be `SECURE_MQTT` or `HTTPS`.

```
aws iot create-domain-configuration \
    --domain-configuration-name domainConfigurationName \
    --authentication-type CUSTOM_AUTH_X509 \  
    --application-protocol SECURE_MQTT \ 
    --authorizer-config '{
        "defaultAuthorizerName": my-custom-authorizer
    }'
```

If you already have a domain configuration, use the [https://docs.aws.amazon.com//cli/latest/reference/iot/update-domain-configuration.html](https://docs.aws.amazon.com//cli/latest/reference/iot/update-domain-configuration.html) command update `authenticationType` and `applicationProtocol` if needed. Note that you can't change the authentication type or protocol on the default endpoint (`iot:Data-ATS`).

```
aws iot update-domain-configuration \
    --domain-configuration-name domainConfigurationName \
    --authentication-type CUSTOM_AUTH_X509 \  
    --application-protocol SECURE_MQTT \
    --authorizer-config '{
        "defaultAuthorizerName": my-custom-authorizer
    }'
```

`domain-configuration-name`  
The name of the domain configuration.

`authentication-type`  
The authentication type of the domain configuration. For more information, see [choosing an authentication type](protocols.md#connection-protocol-auth-mode).

`application-protocol`  
The application protocol which devices use to communicate with AWS IoT Core. For more information, see [choosing an application protocol](protocols.md#protocol-selection).

`--authorizer-config`  
An object that specifies the authorizer configuration in a domain configuration.

`defaultAuthorizerName`  
The name of the authorizer for a domain configuration.

For more information, see [CreateDomainConfiguration](https://docs.aws.amazon.com//iot/latest/apireference/API_CreateDomainConfiguration.html) and [UpdateDomainConfiguration](https://docs.aws.amazon.com//iot/latest/apireference/API_UpdateDomainConfiguration.html) from the *AWS IoT API Reference*. For more information about domain configuration, see [Domain configurations](https://docs.aws.amazon.com//iot/latest/developerguide/iot-custom-endpoints-configurable.html).

# Connecting to AWS IoT Core by using custom authentication


 Devices can connect to AWS IoT Core by using custom authentication with any protocol that AWS IoT Core supports for device messaging. For more information about supported communication protocols, see [Device communication protocols](protocols.md).  The connection data that you pass to your authorizer Lambda function depends on the protocol you use. For more information about creating your authorizer Lambda function, see [Defining your Lambda function](custom-auth-lambda.md). The following sections explain how to connect to authenticate by using each supported protocol.

## HTTPS


Devices sending data to AWS IoT Core by using the [HTTP Publish API](https://docs.aws.amazon.com/iot/latest/apireference/API_iotdata_Publish.html) can pass credentials either through request headers or query parameters in their HTTP POST requests. Devices can specify an authorizer to invoke by using the `x-amz-customauthorizer-name` header or query parameter. If you have token signing enabled in your authorizer, you must pass the `token-key-name` and `x-amz-customauthorizer-signature` in either request headers or query parameters. Note that the `token-signature` value must be URL-encoded when using JavaScript from within the browser.

**Note**  
The customer authorizer for the HTTPS protocol only supports publish operations. For more information about the HTTPS protocol, see [Device communication protocols](protocols.md).

The following example requests show how you pass these parameters in both request headers and query parameters. 

```
//Passing credentials via headers
POST /topics/topic?qos=qos HTTP/1.1
Host: your-endpoint 
x-amz-customauthorizer-signature: token-signature
token-key-name: token-value 
x-amz-customauthorizer-name: authorizer-name

//Passing credentials via query parameters
POST /topics/topic?qos=qos&x-amz-customauthorizer-signature=token-signature&token-key-name=token-value HTTP/1.1
```

## MQTT


 Devices connecting to AWS IoT Core by using an MQTT connection can pass credentials through the `username` and `password` fields of MQTT messages. The `username` value can also optionally contain a query string that passes additional values (including a token, signature, and authorizer name) to your authorizer. You can use this query string if you want to use a token-based authentication scheme instead of `username` and `password` values.  

**Note**  
 Data in the password field is base64-encoded by AWS IoT Core. Your Lambda function must decode it. 

 The following example contains a `username` string that contains extra parameters that specify a token and signature.  

```
username?x-amz-customauthorizer-name=authorizer-name&x-amz-customauthorizer-signature=token-signature&token-key-name=token-value
```

To invoke an authorizer, devices connecting to AWS IoT Core by using MQTT and custom authentication must connect on port 443. They also must pass the Application Layer Protocol Negotiation (ALPN) TLS extension with a value of `mqtt` and the Server Name Indication (SNI) extension with the host name of their AWS IoT Core data endpoint. To avoid potential errors, the value for `x-amz-customauthorizer-signature` should be URL encoded. We also highly recommend that the values of `x-amz-customauthorizer-name` and `token-key-name` be URL encoded. For more information about these values, see [Device communication protocols](protocols.md). The V2 [AWS IoT Device SDKs, Mobile SDKs, and AWS IoT Device Client](iot-sdks.md) can configure both of these extensions. 

## MQTT over WebSockets


 Devices connecting to AWS IoT Core by using MQTT over WebSockets can pass credentials in one of the two following ways. 
+ Through request headers or query parameters in the HTTP UPGRADE request to establish the WebSockets connection.
+ Through the `username` and `password` fields in the MQTT CONNECT message.

 If you pass credentials through the MQTT connect message, the ALPN and SNI TLS extensions are required. For more information about these extensions, see [MQTT](#custom-auth-mqtt).   The following example demonstrates how to pass credentials through the HTTP Upgrade request. 

```
GET /mqtt HTTP/1.1
Host: your-endpoint 
Upgrade: WebSocket 
Connection: Upgrade 
x-amz-customauthorizer-signature: token-signature
token-key-name: token-value 
sec-WebSocket-Key: any random base64 value 
sec-websocket-protocol: mqtt 
sec-WebSocket-Version: websocket version
```

## Signing the token


You must sign the token with the private key of the public-private key pair that you used in the `create-authorizer` call. The following examples show how to create the token signature by using a UNIX-like command and JavaScript. They use the SHA-256 hash algorithm to encode the signature.

------
#### [ Command line ]

```
echo -n TOKEN_VALUE | openssl dgst -sha256 -sign PEM encoded RSA private key | openssl base64
```

------
#### [ JavaScript ]

```
const crypto = require('crypto')

const key = "PEM encoded RSA private key"

const k = crypto.createPrivateKey(key)
let sign = crypto.createSign('SHA256')
sign.write(t)
sign.end()
const s = sign.sign(k, 'base64')
```

------

# Troubleshooting your authorizers


 This topic walks through common issues that can cause problems in custom authentication workflows and steps for resolving them. To troubleshoot issues most effectively, enable CloudWatch logs for AWS IoT Core and set the log level to **DEBUG**. You can enable CloudWatch logs in the AWS IoT Core console ([https://console.aws.amazon.com/iot/](https://console.aws.amazon.com/iot/)). For more information about enabling and configuring logs for AWS IoT Core, see [Configure AWS IoT logging](configure-logging.md). 

**Note**  
If you leave the log level at **DEBUG** for long periods of time, CloudWatch might store large amounts of logging data. This can increase your CloudWatch charges. Consider using resource-based logging to increase the verbosity for only devices in a particular thing group. For more information about resource-based logging, see [Configure AWS IoT logging](configure-logging.md). Also, when you're done troubleshooting, reduce the log level to a less verbose level.

Before you start troubleshooting, review [Understanding the custom authentication workflow](custom-authorizer.md) for a high-level view of the custom authentication process. This helps you understand where to look for the source of a problem.

This topic discusses the following two areas for you to investigate.
+ Issues related to your authorizer's Lambda function.
+ Issues related to your device.

## Check for issues in your authorizer’s Lambda function


Perform the following steps to make sure that your devices’ connection attempts are invoking your Lambda function.

1. Verify which Lambda function is associated with your authorizer.

   You can do this by calling the [DescribeAuthorizer](https://docs.aws.amazon.com/iot/latest/apireference/API_DescribeAuthorizer.html) API or by clicking on the desired authorizer in the **Secure** section of the AWS IoT Core console.

1. Check the invocation metrics for the Lambda function. Perform the following steps to do this.

   1. Open the AWS Lambda console ([https://console.aws.amazon.com/lambda/](https://console.aws.amazon.com/lambda/)) and select the function that is associated with your authorizer.

   1. Choose the **Monitor** tab and view metrics for the time frame that is relevant to your problem.

1. If you see no invocations, verify that AWS IoT Core has permission to invoke your Lambda function. If you see invocations, skip to the next step. Perform the following steps to verify that your Lambda function has the required permissions.

   1. Choose the **Permissions** tab for your function in the AWS Lambda console.

   1. Find the **Resource-based Policy** section at the bottom of the page. If your Lambda function has the required permissions, the policy looks like the following example.  
****  

      ```
      {
        "Version":"2012-10-17",		 	 	 
        "Id": "default",
        "Statement": [
          {
            "Sid": "Id123",
            "Effect": "Allow",
            "Principal": {
              "Service": "iot.amazonaws.com"
            },
            "Action": "lambda:InvokeFunction",
            "Resource": "arn:aws:lambda:us-east-1:111111111111:function:FunctionName",
            "Condition": {
              "ArnLike": {
                "AWS:SourceArn": "arn:aws:iot:us-east-1:111111111111:authorizer/AuthorizerName"
              },
              "StringEquals": {
                "AWS:SourceAccount": "111111111111"
              }
            }
          }
        ]
      }
      ```

   1. This policy grants the `InvokeFunction` permission on your function to the AWS IoT Core principal. If you don't see it, you'll have to add it by using the [AddPermission](https://docs.aws.amazon.com/lambda/latest/dg/API_AddPermission.html) API. The following example shows you how to do this by using the AWS CLI.

      ```
      aws lambda add-permission --function-name FunctionName --principal iot.amazonaws.com --source-arn AuthorizerARn --statement-id Id-123 --action "lambda:InvokeFunction"
      ```

1. If you see invocations, verify that there are no errors. An error might indicate that the Lambda function isn't properly handling the connection event that AWS IoT Core sends to it.

   For information about handling the event in your Lambda function, see [Defining your Lambda function](custom-auth-lambda.md). You can use the test feature in the AWS Lambda console ([https://console.aws.amazon.com/lambda/](https://console.aws.amazon.com/lambda/)) to hard-code test values in the function to make sure that the function is handling events correctly.

1. If you see invocations with no errors, but your devices are not able to connect (or publish, subscribe, and receive messages), the issue might be that the policy that your Lambda function returns doesn't give permissions for the actions that your devices are trying to take. Perform the following steps to determine whether anything is wrong with the policy that the function returns.

   1. Use an Amazon CloudWatch Logs Insights query to scan logs over a short period of time to check for failures. The following example query sorts events by timestamp and looks for failures.

      ```
      display clientId, eventType, status, @timestamp | sort @timestamp desc | filter status = "Failure"    
      ```

   1. Update your Lambda function to log the data that it's returning to AWS IoT Core and the event that triggers the function. You can use these logs to inspect the policy that the function creates.

1. If you see invocations with no errors, but your devices are not able to connect (or publish, subscribe, and receive messages), another reason can be that your Lambda function exceeds the timeout limit. The Lambda function timeout limit for custom authorizer is 5 seconds. You can check the function duration in CloudWatch logs or metrics. 

## Investigating device issues


If you find no issues with invoking your Lambda function or with the policy that the function returns, look for problems with your devices' connection attempts. Malformed connection requests can cause AWS IoT Core not to trigger your authorizer. Connection problems can occur at both the TLS and application layers.

**Possible TLS layer issues:**
+ Customers must pass either a hostname header (HTTP, MQTT over WebSockets) or the Server Name Indication TLS extension (HTTP, MQTT over WebSockets, MQTT) in all custom authentication requests. In both cases, the value passed must match one of your account’s AWS IoT Core data endpoints. These are the endpoints that are returned when you perform the following CLI commands.
  + `aws iot describe-endpoint --endpoint-type iot:Data-ATS`
  + `aws iot describe-endpoint --endpoint-type iot:Data` (for legacy VeriSign endpoints)
+ Devices that use custom authentication for MQTT connections must also pass the Application Layer Protocol Negotiation (ALPN) TLS extension with a value of `mqtt`.
+ Custom authentication is currently available only on port 443.

**Possible application layer issues:**
+ If signing is enabled (the `signingDisabled` field is false in your authorizer), look for the following signature issues.
  + Make sure that you're passing the token signature in either the `x-amz-customauthorizer-signature`header or in a query string parameter.
  + Make sure that the service isn't signing a value other than the token.
  + Make sure that you pass the token in the header or query parameter that you specified in the `token-key-name` field in your authorizer.
+ Make sure that the authorizer name you pass in the `x-amz-customauthorizer-name` header or query string parameter is valid or that you have a default authorizer defined for your account.