# Authentication

APIs are secured using OAuth 2.0

Once you deploy an API, you should see the api_url and token_url output. Using the token url you can get an access token using basic auth, then use that token as bearer token to send mutations and queries to the API URL. For a quick test we recommend Insomnia.

# Receiving Credentials

The API is secured using oAuth 2.0 with scopes provided through a JWT Access Token.

For security reasons the client ID and client secret are not visible in the output, you would need to get those values from AWS Cognito Console to be able to authenticate and get an access token:

  1. login into your AWS account
  2. open the Cognito service
  3. select "User pools" from the side bar
  4. open your newly created user pool
  5. click on the tab "App Integration"
  6. scroll down to the app clients and open your client
  7. find your client ID and show the client secret

# Receiving Access Token

With your client ID and the client secret you can now receive your access token which will be valid for one hour (for changing this value refer to access token validity duration):

curl -u <client_id>:<client_secret> \
--url <token_url> \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data grant_type=client_credentials \
--data 'scope=tilores/mutation.submit tilores/query.search tilores/query.entity'

If you wonder about the scopes, please refer to the authorization documentation for more details.

Now that you have the access token, you can use it for making requests to the API:

curl --request POST \
  --url <api_url> \
  --header 'Authorization: Bearer <access_token>' \
  --header 'Content-Type: application/json' \
  --data '<data is dependent on the query/mutation>'

Example Mutation:

curl --request POST \
  --url <api_url> \
  --header 'Authorization: Bearer <access_token>' \
  --header 'Content-Type: application/json' \
  --data '{"query":"mutation MySubmission($record: RecordInput!) {submit(input:{records:[$record]}){recordsAdded}}","variables":{"record":{"id":"abc","myCustomField":"some value"}},"operationName":"MySubmission"}'

Example Query:

curl --request POST \
  --url <api_url> \
  --header 'Authorization: Bearer <access_token>' \
  --header 'Content-Type: application/json' \
  --data '{"query":"query MySearch($search: SearchParams!) {search(input:{parameters:$search}){entities {id}}}","variables":{"search":{"myCustomField":"some value"}},"operationName":"MySearch"}'

# Multiple Clients

You can easily create multiple clients (users) for the default implementation. In the cognito module in deployment/tilores/main.tf simply add another client:

module "cognito" {
  # other properties
  clients = {
    client = {
      allowed_scopes = [
        # list of allowed scopes
      ]
    },
    other_client = {
      allowed_scopes = [
        # list of allowed scopes
      ]
    }
  }
}

# Custom Authentication

The default deployment of the API provides a simple way to secure your deployment with a standard oAuth 2.0 workflow. It is intended for machine to machine communication as it is often used within enterprise systems. However, you are free to customize the authentication and authorization completely to any other oAuth 2.0 flow. Also, you don't necessarily have to stick with Cognito. You might want to e.g. try out auth0.com or use your own existing solution.

For replacing the standard authentication, you have to remove the cognito module from deployment/tilores/main.tf and modify the tilores module in the same file accordingly:

module "tilores" {
  # other parameters
  authorizer_audience       = <custom audience>
  authorizer_issuer_url     = <custom issuer url>
}

# IP Allow list

You can easily add an extra layer of protection on the API by providing a list of trusted IP addresses and/or CIDR blocks. You can do so as follows:

module "tilores" {
  # other parameters
  ip_range_allow_list = ["192.168.0.1", "192.168.0.0/24"]
}