CIDM Wrapped Developer Guide for server side authentication

Intended audience

This developer guide / walkthrough of CIDM is aimed specfically at web server based application developers. It is expected that the reader has a basic understanding of REST services, HTML and CSS. There are loads of useful guides and walkthroughs provided by auth0, it is worth searching their site to supplement this guide, try https://auth0.com/docs/quickstart/webapp and https://auth0.com/docs/quickstart/backend as a starting point.

The authentication code flow

If you are running a client-server web application and want to manage the customer athentication process from the server side then you have the option of using the 'authentication code flow' method (explained in detail here). This method does not utilize the profile widget and therefore requires your server to entirely manage the user session and login/logout state. It is simple to get working however will require additional coding / plugging into an existing security library of your choosing (e.g. in the case of Java, the Spring Security framework is a common choice). The steps are as follows:

The steps discussed in depth in the next sections.

Creating a login link

You can use a library to create a login link, for example there is a Java library here: https://auth0.com/docs/quickstart/webapp/java-spring-security-mvc/01-login. However if you can't find a suitable library for your server-side language then a link can be constructed manually.

The structure of a login URL is as follows:

https://[auth-domain]/authorize?

client_id=[your-client-id]

&response_type=code

&audience=https://auth.staging-services.qld.gov.au

&scope=openid%20[Level_1 or Level_2]

&login_hint=[CIDM-AAL1 or CIDM-AAL2]

&redirect_uri=[Your callback URL]

Here is a working example:

https://login.auth.staging-services.qld.gov.au/authorize?

client_id=8aqIFVFNrhpws8dv3W5C3FANUMfiqzK7

&response_type=code

&audience=https://auth.staging-services.qld.gov.au

&scope=openid%20Level_1&login_hint=CIDM-AAL1

&redirect_uri=https://servicesmadesimpler.govnet.qld.gov.au/qgcidm/demo/wrapped-server-side-auth/

Try it!

Have a look in the URL bar when you return (you should see a code in the response).

Processing authentication response

When users are successfully returned to your callback URL your webserver will have access to the 'code' querystring parameter. The code is not much use on its own, however it is an opaque string which enables server side retrieval of an OIDC conformant access token. The code should be collected and stored in memory for the next step.

Getting an Access Token

In order to authenticate a user to CIDM Wrapped, you need an access token. Since you are getting the access token from the server side, it will last 2 hours. Getting an access token is a simple POST request to our authentication service as detailed below:

Endpoint: https://login.auth.staging-services.qld.gov.au/oauth/token
Header: Content-Type: application/json
Body:
{
"grant_type": "authorization_code",
"client_id": "YOUR_CLIENT_ID",
"client_secret": "YOUR_CLIENT_SECRET",
"code": "YOUR_AUTHORIZATION_CODE",
"redirect_uri": "https://YOUR_APP/callback" //The URL must match exactly the redirect_uri passed to /authorize
}

Example body:
{
"grant_type": "authorization_code",
"client_id": "8aqIFVFNrhpws8dv3W5C3FANUMfiqzK7",
"client_secret": "di4dUO8Fwe**********7CWeq1O6",
"code": "AqPbbOoXvmTQIhVI",
"redirect_uri": "https://servicesmadesimpler.govnet.qld.gov.au/qgcidm/demo/wrapped-server-side-auth/"
}

Example 200 response:
{
"access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6Ik9EazVRekU0UkRJeVJUazNRekkwTWtJNU1rSkdNamxCTTBOQ016WXlRVVpETUVZeU5VUTRSQSJ9.eyJodHRwczovL2F1dGguc3RhZ2luZy1zZXJ2aWNlcy5xbGQuZ292LmF1L3Nlc3Npb25faWQiOiI1ZWU3NjE2MjIyNzUwOWQ5MDAyYzZmZWM1YjNkOTAzNGFjMGI1NDYxOTRmYmJmYjY1ZTAyYjA4ODhlZWU2Yzk3IiwiaHR0cHM6Ly9hdXRoLnN0YWdpbmctc2VydmljZXMucWxkLmdvdi5hdS9wYXJ0bmVyIjoiQ0lETS1BQUwxIiwiaHR0cHM6Ly9hdXRoLnN0YWdpbmctc2VydmljZXMucWxkLmdvdi5hdS9wYXJ0bmVyX2tleSI6IjBmYTZiMjkwMmJkMDU4ZTY4MjViMmYxNjVjODhlZTUyZmVhMDZjOWFiODA4MzE5ZDlmNjY2MDlhNzUyNGRmMTY0YjAwMWVjODNkMDNlNTcyYjVhNDkxZTcwZjQwNTAyZjlhZGY4YWQ3YzE0ZDRjOTI2YjFkN2FhMzUzZThlMmNjNjNhMmY5NjIwNjFiMDFiMTJlYmFmZWQ3MTQ0OTk2OWEwMDUzYWRlYmZmYzBlMGQ0ZWFhYzhiNTE2N2YzZDA5Y2RhMmY3N2JkNGEwNTFlMWVlZDI4NzYxYmVkNzIzMzIwNDQxNWFjODQ0OGVlZmVjMmNkNWIxODFjZGE1MTU2ZWM1MDczNzllMGNhZDkzNmJkNTU0OSIsImh0dHBzOi8vYXV0aC5zdGFnaW5nLXNlcnZpY2VzLnFsZC5nb3YuYXUvcWlkIjoiZGFlZDQ5YzgtMGY5Ny00NGM0LTlkNjMtOTI4NzdhMWM2MTkxIiwiaHR0cHM6Ly9hdXRoLnN0YWdpbmctc2VydmljZXMucWxkLmdvdi5hdS9sYXN0X2xvZ2luIjoiMjAxOC0xMC0zMFQwNDo0OTo1NC42NzdaIiwiaXNzIjoiaHR0cHM6Ly91YXQucWxkLWdvdi1zdGcuYXV0aDAuY29tLyIsInN1YiI6InNhbWxwfENJRE0tQUFMMXxkYWVkNDljOC0wZjk3LTQ0YzQtOWQ2My05Mjg3N2ExYzYxOTEiLCJhdWQiOlsiaHR0cHM6Ly9hdXRoLnN0YWdpbmctc2VydmljZXMucWxkLmdvdi5hdSIsImh0dHBzOi8vdWF0LnFsZC1nb3Ytc3RnLmF1dGgwLmNvbS91c2VyaW5mbyJdLCJpYXQiOjE1NDA4Nzc3MTMsImV4cCI6MTU0MDk2NDExMywiYXpwIjoiOGFxSUZWRk5yaHB3czhkdjNXNUMzRkFOVU1maXF6SzciLCJzY29wZSI6Im9wZW5pZCJ9.FgoAP7DDCPKfahi3tx07zLNmo1hzidSjluIXJxOdbB3SWc5XoyHEC5n-qdm0wtZepjsezGHYXXGIZ1igXxPTpC262QBz_x98EXto-KUCu8mPkYEVkyJS5ssuPQLgP7eK5cDGPlMRomDpdRjJsKbcOIv5uXs8gd1Kb9cEScDm0WZ3Jk7voQM82uBQI8Kl_17AP72XIACvGuZBlFF4oDanOzk6NZfDWdmPIeo08dgla-1MBy-ZevhNIIb8YcHvi0TTwItIfE1-WQ_4OxaHVDHMIP1AJHv-WmzjS6iua66CbzEKj57O6UPb1WdFBFUeuVCBAoxZi_WOp-6BaWtEHfgZiQ",
"id_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6Ik9EazVRekU0UkRJeVJUazNRekkwTWtJNU1rSkdNamxCTTBOQ016WXlRVVpETUVZeU5VUTRSQSJ9.eyJodHRwczovL2F1dGguc3RhZ2luZy1zZXJ2aWNlcy5xbGQuZ292LmF1L2VtYWlsIjoibXItYW5kZXJzb25Ac3BsYXNoLmNvbSIsImh0dHBzOi8vYXV0aC5zdGFnaW5nLXNlcnZpY2VzLnFsZC5nb3YuYXUvcGljdHVyZSI6Imh0dHBzOi8vcy5ncmF2YXRhci5jb20vYXZhdGFyL2U1ZWIxNTkwYzYzMDU3OGVlM2FjMWU3Yzc2MzI2MTVkP3M9NDgwJnI9cGcmZD1odHRwcyUzQSUyRiUyRmNkbi5hdXRoMC5jb20lMkZhdmF0YXJzJTJGbXIucG5nIiwiaHR0cHM6Ly9hdXRoLnN0YWdpbmctc2VydmljZXMucWxkLmdvdi5hdS91c2VyX2lkIjoic2FtbHB8Q0lETS1BQUwxfGRhZWQ0OWM4LTBmOTctNDRjNC05ZDYzLTkyODc3YTFjNjE5MSIsImh0dHBzOi8vYXV0aC5zdGFnaW5nLXNlcnZpY2VzLnFsZC5nb3YuYXUvYXV0aGVudGljYXRpb25tZXRob2QiOiJ1cm46YXU6cWxkOmdvdjphdXRobjpuYW1lczpTQU1MOjIuMDphYzpBQUwyOklSQUwyOklBQUwyIiwiaHR0cHM6Ly9hdXRoLnN0YWdpbmctc2VydmljZXMucWxkLmdvdi5hdS9jbGllbnRJRCI6IjhhcUlGVkZOcmhwd3M4ZHYzVzVDM0ZBTlVNZmlxeks3IiwiaHR0cHM6Ly9hdXRoLnN0YWdpbmctc2VydmljZXMucWxkLmdvdi5hdS9hcHBfbWV0YWRhdGEiOnsibmFtZSI6ImUzNmVmZTNiMzNkZjdmNDBjMDI4ZTJlYmE1ODVkMjJlMzRmMzU2YWE5ZDg2Y2QyYTM4NmZmNWJhNjE0Y2RiZDdmMDU0MjQ5OTQ4MWZhZTgwZjFkZmVlNjg1MDZkZWUyNTY3ODY5NzQwNThhNjU3N2ZjN2E3YjEyNDE5ZmYwNGRhYzJiNjEwNzc3NjAwZmZlNWU0ODk4ZWUwZTIzMDUzZWY3MDkwNjM0NjI4NjI3M2ViMmZkNTE3MTQ1OTFlNzQxOTE1NjkxMGZjZDI0ODVjNzlkODUyYjEyM2ZhYzI0ZDQ4N2I1ZiIsIm5pY2tuYW1lIjoiZTgyNzU2Nzk0ZDU3ZDBjMzY0Nzc1ZTA3Y2JmZTgzN2Y4MWM1MWQyNTc3MzJkYTMxZjAwNzg4M2IwZGUxMzNiNmExYTdhYmMzYjZiMDlmN2NlM2MxOTIzNGU3MDkyZTYxOWFhMzVmYjU1NjQwODI0YjNjOWQwZjFlM2RmMGUzOWViYzIyMmQwM2NlNTc5NjU0YjEwMjM1Yzg0MWU1MzRhZTQ4ODAyZTU4Y2RiOGYyMTVmMjFiNGViMDE2ZDU4Y2NiNzJmZGMyNWQ1YWNjZWMiLCJfZW5jcnlwdGVkIjp7Im5hbWUiOnRydWUsIm5pY2tuYW1lIjp0cnVlfSwic29tZV9maWVsZCI6IlkiLCJwcmV2aW91c19sb2dpbiI6IjIwMTgtMTAtMzBUMDQ6NDk6NTQuNjc3WiIsInFpZCI6ImRhZWQ0OWM4LTBmOTctNDRjNC05ZDYzLTkyODc3YTFjNjE5MSIsInNjb3BlIjoib3BlbmlkIExldmVsXzEifSwiaHR0cHM6Ly9hdXRoLnN0YWdpbmctc2VydmljZXMucWxkLmdvdi5hdS9TaGFyaW5nUHJlZmVyZW5jZSI6IlkiLCJpc3MiOiJodHRwczovL3VhdC5xbGQtZ292LXN0Zy5hdXRoMC5jb20vIiwic3ViIjoic2FtbHB8Q0lETS1BQUwxfGRhZWQ0OWM4LTBmOTctNDRjNC05ZDYzLTkyODc3YTFjNjE5MSIsImF1ZCI6IjhhcUlGVkZOcmhwd3M4ZHYzVzVDM0ZBTlVNZmlxeks3IiwiaWF0IjoxNTQwODc3NzEzLCJleHAiOjE1NDA4ODQ5MTN9.RJMXT9ztO2S-Xlz7vjyPNMZLdHtAiJQ-EOev_92ZtvNbUhiPaH1uJftc8CyzPjSIDGdQpL-s3OoerZXETLaoU2yK-NlVXP_8nR-sv47ZHPfMaGjMkGXMBstEp2iOoVJuwYm7qQXRdqdhD9YCNAD-Dfain6RQ5IoMSEfhIEdsiC4bjzED_KNeNeiLtPGMXtem-gdf9134cc4uiuLFzrBKlSv5dTTweGqgcuFpqkkoekS6DSTbXFI9WJqW3Vbwed0j5BWsqJtaeoKYu_2mUkxRalqn9pj9TRuG8B4HU4hMpMvL6_jHIZ-vVpEntQXOaB3cTZ1bTL39XbbdaiTd3zrMbg",
"scope": "openid",
"expires_in": 86400,
"token_type": "Bearer"
}

Example 4** response:
{
"error": "invalid_grant",
"error_description": "Invalid authorization code"
}

Integrating the Access Token and ID Token

The tokens returned via the authentication code flow are JWTs and conform to Open ID Connect standards. There is no need to validate these tokens since they are retrieved directly from the authentication service. You can decode the ID token (JWT anatomy info at jwt.io) and retrieve any necessary values. You can attach the access token to your http session management and security framework. There are plenty of libraries out there which can facilitate this process and auth0 provides numerous quickstart guides at https://auth0.com/docs/quickstart/backend.

Calling the Customer Attribute API from your server-side

In the browser, the $.qgcidm object looks after calling the Customer Attributes API, however if you are verifying a JWT on your server-side then you will need to make a request to the Customer Attributes API directly. This is a REST based API which is aimed to be simple, multi-purposed and compatible with future identity and attribute release frameworks. It handles JWT verification and attribute release in the one API call. Currently it only supports the attributes attached to a QGCIDM account and will be expanded upon in 2019. You can call the Customer Attributes API using a simple GET request from whichever server-side HTTP request library of your choosing.

Call the test version Customer Attributes API using the following configurations:

Endpoint (UAT)

https://api-customer-attributes.auth.staging-services.qld.gov.au/v1/customer_attributes

Request Method

HTTP GET

Request Headers

authorization : <Customers JWT Token> x-api-key (this is only for testing, won't work in production) : c93B17fVMbaagCAeibtgC6nbiM9ZbJkD2ST1lnfD

Query Parameters (comma separated per attribute type, see Getting Started guide for full list of attributes)

authoritative_attributes=QID,DateOfBirth,Email,UserId,AuthenticationMethod,FirstName,FamilyName&self_asserted_attributes=Name,Picture,FirstName,FamilyName&sign=false

Response format

A successful request (200) will return a JSON formatted response similar to that found in $.qgcidm.profile.attributes. Anything other than 200 indicates a failure in authentication (typically 4xx) or service availability issue (typically 5xx)

Specific documentation will be produced to cover the details of the Custommer Attributes API, in the mean time please refer to the Swagger API definition below for more details:

---
swagger: "2.0"
info:
  version: "2017-11-06T11:38:32Z"
  title: "CIDM NEO Customer Attributes API"
  description: |
    The Customer Attributes API supports the retrieval or both Verified and Unverified Customer Attributes
    
    ## Version History:
    * 0.1 Initial Draft of Customer Attributes API.
    * 0.2 Updated to have a POST and a GET for Customer Attributes.  The GET being a less complex API/request.
    * 0.3 Removed QID from Urls as they're not available in the JWT
    * 0.4 Renamed resources to customer_shared and customer_attributes

    ## Security:
    1. Requires AWS API Gateway Key in the x-api-key header
    2. Requires Auth0 User JWT in the Authorization header

    ## Usage:

    ### Customer Sharing Preferences

    #### Request:
    ```

    export CUSTOMER_JWT=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwczovL2Rldi5xbGQtZ292LWRldi5hdXRoMC5jb20vIiwic3ViIjoiZ29vZ2xlLW9hdXRoMnwxMDU1MTcyMjA0MzQ1NjM4MDY1NTkiLCJhdWQiOiJLdTFseE1rQlFXY0NETHF1Q1BDNXpvc1cxdmhSTWtvWiIsImV4cCI6MTUxMDYyMTEzNiwiaWF0IjoxNTEwNjEzOTM2fQ.Kt7ifNQlA9IlUoncFRmaGsE5Gx1f8i87ukwl7QdQvRw
    export API_KEY=cc2f0cbd-be66-431f-8b86-2f8d5ea30625

    curl -v -H "Content-Type: application/json" -H "Accept: application/json" -H "x-api-key: ${API_KEY}" -H "Authorization: Bearer ${CUSTOMER_JWT}" https://api-customer-attributes.identity.test-services.qld.gov.au/v1/customer_shared
    ```
    #### Response:
    ```JSON

    {
      "share" : "NOT_ALWAYS"
    }
    ```

    ### Customer Attributes

    #### Request:
    ```

    export CUSTOMER_JWT=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwczovL2Rldi5xbGQtZ292LWRldi5hdXRoMC5jb20vIiwic3ViIjoiZ29vZ2xlLW9hdXRoMnwxMDU1MTcyMjA0MzQ1NjM4MDY1NTkiLCJhdWQiOiJLdTFseE1rQlFXY0NETHF1Q1BDNXpvc1cxdmhSTWtvWiIsImV4cCI6MTUxMDYyMTEzNiwiaWF0IjoxNTEwNjEzOTM2fQ.Kt7ifNQlA9IlUoncFRmaGsE5Gx1f8i87ukwl7QdQvRw
    export API_KEY=cc2f0cbd-be66-431f-8b86-2f8d5ea30625


    curl -v -H "Content-Type: application/json" -H "Accept: application/json" -H "x-api-key: ${API_KEY}" -H "Authorization: Bearer ${CUSTOMER_JWT}" https://api-customer-attributes.identity.test-services.qld.gov.au/v1/customer_attributes?authoritative_attributes=QID,DateOfBirth,Email&self_asserted_attributes=Name,UserId,AuthenticationMethod,Picture,FirstName,FamilyName,Nickname&sign=true

    #Note the below won't actually work on the command line as it's over multiple lines.
    #Actual request value needs to be a URL encoded string of the JSON object. i.e. JSON.stringify(ATTRIBUTES);
    export ATTRIBUTES = "\
      {
        "attributes": [
          {
            "name": "GivenName",
            "definition": {
              "pedigree": "SELF_ASSERTED",
              "signed": true,
            }
          },
          {
            "name": "FamilyName",
            "definition": {
              "pedigree": "AUTHORITATIVE",
              "signed": true,
            }
          },
          {
            "name" : "Senior",
            "definition": {
              "source": "FORMULA",
              "formula" : "Age >= 65"
            }
          }
          ]
      }"

    curl -v -H "Content-Type: application/json" -H "Accept: application/json" -H "x-api-key: ${API_KEY}" -H "Authorization: Bearer ${CUSTOMER_JWT}" https://api-customer-attributes.identity.test-services.qld.gov.au/v1/customer_attributes?attributes=${ATTRIBUTES}

    ```
    #### Response:
    ```JSON
    {
      "attributes" : [
        {
          "name" : "GivenName",
          "value": "Jeremy",
          "metadata" : [
            {
              "name": "pedigree",
              "value": "SELF_ASSERTED"
            }
          ],
          "definition": {
            "source": "ATTRIBUTE",
            "pedigree": "SELF_ASSERTED",
            "signed": true,
          }
        },
        {
          "name" : "FamilyName",
          "value": "Ford",
          "metadata" : [
            {
              "name": "pedigree",
              "value": "AUTHORITATIVE"
            }
          ],
          "definition": {
            "source": "ATTRIBUTE",,
            "pedigree": "AUTHORITATIVE",
            "signed": true,
          }
        },
        {
          "name" : "Senior",
          "value": "false",
          "metadata" : [
            {
              "name": "pedigree",
              "value": "AUTHORITATIVE"
            }
          ],
          "definition": {
            "source": "FORMULA",
            "signed": false,
            "formula" : "Age >= 65"
          }
        }

      ],
      "signed_attributes" : "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwczovL2Rldi5xbGQtZ292LWRldi5hdXRoMC5jb20vIiwic3ViIjoiZ29vZ2xlLW9hdXRoMnwxMDU1MTcyMjA0MzQ1NjM4MDY1NTkiLCJhdWQiOiJLdTFseE1rQlFXY0NETHF1Q1BDNXpvc1cxdmhSTWtvWiIsImV4cCI6MTUxMDYyMTEzNiwiaWF0IjoxNTEwNjEzOTM2fQ.Kt7ifNQlA9IlUoncFRmaGsE5Gx1f8i87ukwl7QdQvRw"
    }
    ```

    ### Verify Customer Attributes

    #### Request:
    ```

    export SIGNED_ATTRIBUTES_JWT=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwczovL2Rldi5xbGQtZ292LWRldi5hdXRoMC5jb20vIiwic3ViIjoiZ29vZ2xlLW9hdXRoMnwxMDU1MTcyMjA0MzQ1NjM4MDY1NTkiLCJhdWQiOiJLdTFseE1rQlFXY0NETHF1Q1BDNXpvc1cxdmhSTWtvWiIsImV4cCI6MTUxMDYyMTEzNiwiaWF0IjoxNTEwNjEzOTM2fQ.Kt7ifNQlA9IlUoncFRmaGsE5Gx1f8i87ukwl7QdQvRw

    export API_KEY=cc2f0cbd-be66-431f-8b86-2f8d5ea30625


    curl -v -H "Content-Type: application/json" -H "Accept: application/json" -H "x-api-key: ${API_KEY}" -d '{"signed_attributes" :"${SIGNED_ATTRIBUTES_JWT}"}' https://api-customer-attributes.identity.test-services.qld.gov.au/v1/verify_customer_attributes

    ```
    #### Response:
    ```JSON
    {
      "attributes" : [
        {
          "name" : "GivenName",
          "value": "Jeremy",
          "metadata" : [
            {
              "name": "pedigree",
              "value": "AUTHORITATIVE"
            }
          ],
          "definition": {
            "source": "ATTRIBUTE",
            "pedigree": "AUTHORITATIVE",
            "signed": true,
          }
        },
        {
          "name" : "FamilyName",
          "value": "Ford",
          "metadata" : [
            {
              "name": "pedigree",
              "value": "AUTHORITATIVE"
            }
          ],
          "definition": {
            "source": "ATTRIBUTE",,
            "pedigree": "AUTHORITATIVE",
            "signed": true,
          }
        }
    }
    ```




host: "fx7afs9xvf.execute-api.ap-southeast-2.amazonaws.com"
basePath: "/v1"
schemes:
- "https"
paths:
  /health:
    get:
      produces:
      - "application/json"
      responses:
        200:
          description: "200 response"
          schema:
            $ref: '#/definitions/HealthResponse'
          headers:
            Content-Type:
              type: "string"
            Access-Control-Allow-Origin:
              type: "string"
        500:
          description: "Unknown Server Error."
          schema:
            $ref: '#/definitions/Error'
          headers:
            Content-Type:
              type: "string"
            Access-Control-Allow-Origin:
              type: "string"
      security:
      - api_key: []
      x-amazon-apigateway-integration:
        responses:
          default:
            statusCode: "200"
            responseParameters:
              method.response.header.Access-Control-Allow-Origin: "'*'"
        uri: "arn:aws:apigateway:{{ Region }}:lambda:path/2015-03-31/functions/arn:aws:lambda:{{ Region }}:{{ AwsAccount }}:function:{{ LambdaArn }}/invocations"
        passthroughBehavior: "when_no_match"
        httpMethod: "POST"
        contentHandling: "CONVERT_TO_TEXT"
        type: "aws_proxy"

  /customer_shared:
    options:
      consumes:
      - "application/json"
      produces:
      - "application/json"
      responses:
        200:
          description: "200 response"
          headers:
            Access-Control-Allow-Origin:
              type: "string"
            Access-Control-Allow-Methods:
              type: "string"
            Access-Control-Allow-Headers:
              type: "string"
      x-amazon-apigateway-integration:
        responses:
          default:
            statusCode: "200"
            responseParameters:
              method.response.header.Access-Control-Allow-Methods: "'DELETE,GET,HEAD,OPTIONS,PATCH,POST,PUT'"
              method.response.header.Access-Control-Allow-Headers: "'Content-Type,Authorization,X-Amz-Date,X-Api-Key,X-Amz-Security-Token'"
              method.response.header.Access-Control-Allow-Origin: "'*'"
        requestTemplates:
          application/json: "{\"statusCode\": 200}"
        passthroughBehavior: "when_no_match"
        type: "mock"
    get:
      produces:
      - "application/json"
      parameters:
      - name: "Authorization"
        in: "header"
        required: true
        type: "string"
      responses:
        200:
          description: "200 response"
          schema:
            $ref: '#/definitions/CustomerSharingPreference'
          headers:
            Content-Type:
              type: "string"
            Access-Control-Allow-Origin:
              type: "string"
      security:
      - api_key: []
      - auth0JWTAuthorizer: []
      x-amazon-apigateway-request-validator: "params-only"
      x-amazon-apigateway-integration:
        responses:
          default:
            statusCode: "200"
            responseParameters:
              method.response.header.Access-Control-Allow-Origin: "'*'"
        uri: "arn:aws:apigateway:{{ Region }}:lambda:path/2015-03-31/functions/arn:aws:lambda:{{ Region }}:{{ AwsAccount }}:function:{{ LambdaArn }}/invocations"
        passthroughBehavior: "when_no_match"
        httpMethod: "POST"
        contentHandling: "CONVERT_TO_TEXT"
        type: "aws_proxy"

  /customer_attributes:
    options:
      consumes:
      - "application/json"
      produces:
      - "application/json"
      responses:
        200:
          description: "200 response"
          headers:
            Access-Control-Allow-Origin:
              type: "string"
            Access-Control-Allow-Methods:
              type: "string"
            Access-Control-Allow-Headers:
              type: "string"
      x-amazon-apigateway-integration:
        responses:
          default:
            statusCode: "200"
            responseParameters:
              method.response.header.Access-Control-Allow-Methods: "'DELETE,GET,HEAD,OPTIONS,PATCH,POST,PUT'"
              method.response.header.Access-Control-Allow-Headers: "'Content-Type,Authorization,X-Amz-Date,X-Api-Key,X-Amz-Security-Token'"
              method.response.header.Access-Control-Allow-Origin: "'*'"
        requestTemplates:
          application/json: "{\"statusCode\": 200}"
        passthroughBehavior: "when_no_match"
        type: "mock"
    get:
      produces:
      - "application/json"
      parameters:
      - name: "authoritative_attributes"
        in: "query"
        description: Comma separated list of Attribute Names that are required at an AUTHORITATIVE pedigree
        required: false
        type: "string"
      - name: "self_asserted_attributes"
        in: "query"
        description: Comma separated list of Attribute Names that are required at atleast a SELF_ASSERTED pedigree
        required: false
        type: "string"
      - name: "sign"
        in: "query"
        description: Boolean flag to indicate if all attributes should be signed
        required: false
        type: "string"
      - name: "Authorization"
        in: "header"
        required: true
        type: "string"
      responses:
        200:
          description: "HTTP 200 Success Response."
          schema:
            $ref: '#/definitions/CustomerAttributesResponse'
          headers:
            Content-Type:
              type: "string"
            Access-Control-Allow-Origin:
              type: "string"
        204:
          description: "No Content.  None of the requested Attributes had a value."
          headers:
            Content-Type:
              type: "string"
            Access-Control-Allow-Origin:
              type: "string"
        400:
          description: "Bad request. No Attributes requested, or at least one invalid Attributes or Formula was provided. Do not attempt the request until the input has been fixed"
          schema:
            $ref: '#/definitions/ValidationError'
          headers:
            Content-Type:
              type: "string"
            Access-Control-Allow-Origin:
              type: "string"
        401:
          description: "Unauthorized request.  Missing, Invalid, or Expired credentials provided"
          headers:
            Content-Type:
              type: "string"
            Access-Control-Allow-Origin:
              type: "string"
        500:
          description: "Unknown Server Error."
          schema:
            $ref: '#/definitions/Error'
          headers:
            Content-Type:
              type: "string"
            Access-Control-Allow-Origin:
              type: "string"
      security:
      - api_key: []
      - auth0JWTAuthorizer: []
      x-amazon-apigateway-request-validator: "params-only"
      x-amazon-apigateway-integration:
        responses:
          default:
            statusCode: "200"
            responseParameters:
              method.response.header.Access-Control-Allow-Origin: "'*'"
        uri: "arn:aws:apigateway:{{ Region }}:lambda:path/2015-03-31/functions/arn:aws:lambda:{{ Region }}:{{ AwsAccount }}:function:{{ LambdaArn }}/invocations"
        passthroughBehavior: "when_no_match"
        httpMethod: "POST"
        cacheNamespace: "gkwi0g"
        cacheKeyParameters:
        - "method.request.querystring.authoritative_attributes"
        - "method.request.querystring.self_asserted_attributes"
        - "method.request.querystring.sign"
        - "method.request.header.Authorization"
        contentHandling: "CONVERT_TO_TEXT"
        type: "aws_proxy"
    post:
      produces:
      - "application/json"
      parameters:
      - name: attributes
        in: body
        description: Attributes to Retrieve
        schema:
          type: object
          items:
            $ref: '#/definitions/CustomerAttributesRequest'
      responses:
        200:
          description: "HTTP 200 Success Response."
          schema:
            $ref: '#/definitions/CustomerAttributesResponse'
          headers:
            Content-Type:
              type: "string"
            Access-Control-Allow-Origin:
              type: "string"
        204:
          description: "No Content.  None of the requested Attributes had a value."
          headers:
            Content-Type:
              type: "string"
            Access-Control-Allow-Origin:
              type: "string"
        400:
          description: "Bad request. No Attributes requested, or at least one invalid Attributes or Formula was provided. Do not attempt the request until the input has been fixed"
          schema:
            $ref: '#/definitions/ValidationError'
          headers:
            Content-Type:
              type: "string"
            Access-Control-Allow-Origin:
              type: "string"
        401:
          description: "Unauthorized request.  Missing, Invalid, or Expired credentials provided"
          headers:
            Content-Type:
              type: "string"
            Access-Control-Allow-Origin:
              type: "string"
        500:
          description: "Unknown Server Error."
          schema:
            $ref: '#/definitions/Error'
          headers:
            Content-Type:
              type: "string"
            Access-Control-Allow-Origin:
              type: "string"
      security:
      - api_key: []
      - auth0JWTAuthorizer: []
      x-amazon-apigateway-integration:
        responses:
          default:
            statusCode: "200"
            responseParameters:
              method.response.header.Access-Control-Allow-Origin: "'*'"
        uri: "arn:aws:apigateway:{{ Region }}:lambda:path/2015-03-31/functions/arn:aws:lambda:{{ Region }}:{{ AwsAccount }}:function:{{ LambdaArn }}/invocations"
        passthroughBehavior: "when_no_match"
        httpMethod: "POST"
        contentHandling: "CONVERT_TO_TEXT"
        type: "aws_proxy"

  /verify_customer_attributes:
    options:
      consumes:
      - "application/json"
      produces:
      - "application/json"
      responses:
        200:
          description: "200 response"
          headers:
            Access-Control-Allow-Origin:
              type: "string"
            Access-Control-Allow-Methods:
              type: "string"
            Access-Control-Allow-Headers:
              type: "string"
      x-amazon-apigateway-integration:
        responses:
          default:
            statusCode: "200"
            responseParameters:
              method.response.header.Access-Control-Allow-Methods: "'DELETE,GET,HEAD,OPTIONS,PATCH,POST,PUT'"
              method.response.header.Access-Control-Allow-Headers: "'Content-Type,Authorization,X-Amz-Date,X-Api-Key,X-Amz-Security-Token'"
              method.response.header.Access-Control-Allow-Origin: "'*'"
        requestTemplates:
          application/json: "{\"statusCode\": 200}"
        passthroughBehavior: "when_no_match"
        type: "mock"
    post:
      produces:
      - "application/json"
      parameters:
        - name: signed_attributes
          in: body
          description: Signed Attributes to verify
          schema:
            type: object
            items:
              $ref: '#/definitions/VerifyAttributesRequest'

      responses:
        200:
          description: "HTTP 200 Success Response."
          schema:
            $ref: '#/definitions/VerifyAttributesResponse'
          headers:
            Content-Type:
              type: "string"
            Access-Control-Allow-Origin:
              type: "string"

        400:
          description: "Bad request. Invalid request payload"
          schema:
            $ref: '#/definitions/ValidationError'
          headers:
            Content-Type:
              type: "string"
            Access-Control-Allow-Origin:
              type: "string"
        401:
          description: "Unauthorized request. Provided signed_attributes value has been tampered with and must not be trusted"
          headers:
            Content-Type:
              type: "string"
            Access-Control-Allow-Origin:
              type: "string"
        500:
          description: "Unknown Server Error."
          schema:
            $ref: '#/definitions/Error'
          headers:
            Content-Type:
              type: "string"
            Access-Control-Allow-Origin:
              type: "string"
      security:
      - api_key: []
      x-amazon-apigateway-integration:
        responses:
          default:
            statusCode: "200"
            responseParameters:
              method.response.header.Access-Control-Allow-Origin: "'*'"
        uri: "arn:aws:apigateway:{{ Region }}:lambda:path/2015-03-31/functions/arn:aws:lambda:{{ Region }}:{{ AwsAccount }}:function:{{ LambdaArn }}/invocations"
        passthroughBehavior: "when_no_match"
        httpMethod: "POST"
        contentHandling: "CONVERT_TO_TEXT"
        type: "aws_proxy"

securityDefinitions:
  api_key:
    type: "apiKey"
    name: "x-api-key"
    in: "header"
  auth0JWTAuthorizer:
    type: "apiKey"
    name: "Authorization"
    in: "header"
    x-amazon-apigateway-authtype: "custom"
    x-amazon-apigateway-authorizer:
      authorizerUri: "arn:aws:apigateway:{{ Region }}:lambda:path/2015-03-31/functions/arn:aws:lambda:{{ Region }}:{{ AwsAccount }}:function:{{ Product}}AuthorizationLambda/invocations"
      authorizerResultTtlInSeconds: 300
      type: "token"

x-amazon-apigateway-gateway-responses:
  DEFAULT_5XX:
    responseParameters:
      gatewayresponse.header.Access-Control-Allow-Methods: "'GET,OPTIONS'"
      gatewayresponse.header.Access-Control-Allow-Origin: "'*'"
      gatewayresponse.header.Access-Control-Allow-Headers: "'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token'"
  DEFAULT_4XX:
    responseParameters:
      gatewayresponse.header.Access-Control-Allow-Methods: "'GET,OPTIONS'"
      gatewayresponse.header.Access-Control-Allow-Origin: "'*'"
      gatewayresponse.header.Access-Control-Allow-Headers: "'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token'"
x-amazon-apigateway-request-validators:
  params-only:
    validateRequestParameters: true
    validateRequestBody: false

definitions:


  CustomerSharingPreference:
    type: object
    required: [share]
    properties:
      share:
        type: string
        enum: [ALWAYS, NOT_ALWAYS]

  CustomerAttributeDefinition:
    type: object
    required: [source]
    properties:
      source:
        type: string
        description: Source of Attribute Value
        enum: [ATTRIBUTE, FORMULA]
        default: ATTRIBUTE
      pedigree:
        type: string
        enum: [AUTHORITATIVE, SELF_ASSERTED]
        default: SELF_ASSERTED
        description: AUTHORITATIVE or SELF_ASSERTED
      signed:
        type: boolean
        default: false
        description: True if the Attribute will be signed in the Response.
      forumla:
        type: string
        description: Formula for calculating the Attribute Value (i.e. 'Age > 65') where source is FORMULA

  CustomerAttributeRequest:
    type: object
    required: [name]
    properties:
      name:
        type: string
        description: Name of the Attribute in the Response
      definition:
        $ref: '#/definitions/CustomerAttributeDefinition'

  AttributeMetadata:
    type: object
    required: [name, value]
    properties:
      name:
        type: string
        description: Name of the Metadata Attribute
      value:
        type: string
        description: Value of the Metadata Attribute


  CustomerAttributesRequest:
    type: object
    required: [attributes]
    properties:
      attributes:
        type: array
        items:
          $ref: '#/definitions/CustomerAttributeRequest'

  CustomerAttributesResponse:
    type: object
    required: [attributes]
    properties:
      attributes:
        type: array
        items:
          $ref: '#/definitions/CustomerAttributeResponse'
      signed_attributes:
        type: string
        description: JWT containing a Payload with each signed Attribute at the top level

  CustomerAttributeResponse:
    type: object
    required: [name, value]
    properties:
      name:
        type: string
        description: Name of the Attribute in the Response
      value:
        type: string
        description: Value of the Attribute in the Response
      metadata:
        type: array
        items:
          $ref: '#/definitions/AttributeMetadata'
      definition:
        $ref: '#/definitions/CustomerAttributeDefinition'

  VerifyAttributesRequest:
    type: object
    required: [signed_attributes]
    properties:
      signed_attributes:
        type: string
        description: JWT returned from the attributes request

  VerifyAttributesResponse:
    type: object
    required: [attributes]
    properties:
      attributes:
        type: array
        items:
          $ref: '#/definitions/CustomerAttributeResponse'

  HealthResponse:
    type: object
    properties:
      status:
        type: string
        
  Error:
    type: object
    properties:
      code:
        type: string
      message:
        type: string
      description:
        type: string
      link:
        type: string

  ValidationFailures:
    type: object
    properties:
      property:
        type: string
        description: Property name
      failure_reason:
        type: string
        description: Failure reason

  ValidationError:
    type: object
    properties:
      code:
        type: string
      message:
        type: string
      description:
        type: string
      link:
        type: string
      validation_failures:
        type: array
        items:
          $ref: '#/definitions/ValidationFailures'