Webhook
Segue abaixo um resumo do fluxo de comunicação entre Developer Portal e webhook durante a solicitação de credenciais:
- 
Desenvolvedor se cadastra no Developer Portal.
 - 
Desenvolvedor vai no menu Apps e cria um novo app AWS (apps do API Manager Sensedia não utilizam webhook).
 - 
Sistema Developer Portal faz uma requisição HTTP ao webhook, passando as informações do app AWS do desenvolvedor.
 - 
Webhook, na sua infraestrutura, recebe a requisição, cria as credenciais e retorna na mesma requisição HTTP.
 - 
Sistema Developer Portal recebe o retorno, grava as credenciais no banco de dados e disponibiliza acesso para o desenvolvedor.
 
Especificação
| 
 É de sua responsabilidade implementar o webhook na sua infraestrutura, mas você pode consultar um exemplo de implementação.  | 
Open API Specification
Para criar o webhook, você deverá implementar este Contrato Open API.
A especificação foi alterada. Foi adicionado o campo customCredentials (opcional), que pode ser udado com API KEY e CLIENT CREDENTIALS.
 | 
Endpoints
Veja abaixo os endpoints que você deverá implementar e os detalhes de requisição e resposta de cada um deles.
| Ação | Endpoint | 
|---|---|
Criar credenciais  | 
  | 
Atualizar credenciais  | 
  | 
Revogar credenciais  | 
  | 
Verificar disponibilidade  | 
  | 
Autenticação
Todos os endpoints utilizarão basic authentication.
Você receberá o header Authorization: Basic <username:password base64> e deverá validá-lo da forma que desejar.
Criar credenciais
POST /v1/createCredentials
Endpoint responsável por criar e retornar as credenciais do app.
Request
- 
Header:
Authorization: Basic <username:password base64>
 - 
Body:
{ "appName": "string", "developer": "string", "apis": [ { "id": "string", "usagePlans": [ { "id": "string" } ] } ] } 
Response
- 
Status code:
200 OK - 
Body:
{ "credentialType": "CLIENT_CREDENTIALS | API_KEY", "clientId": string, "clientSecret": string, "apiKeyId": string, "apiKey": string } 
A resposta pode retornar tanto uma API Key quanto Client Credentials.
Para o credentialType=API_KEY, devem ser retornados os campos apiKeyId e apiKey.
Para o credentialType=CLIENT_CREDENTIALS, devem ser retornados os campos clientId e clientSecret.
A especificação de CreateCredentialsResponse foi alterada. Foi incluído o campo customCredentials (opcional), para retorno de informações adicionais, como API KEY e CLIENT CREDENTIALS.
 | 
Atualizar credenciais
POST /v1/updateCredentials
Request
- 
Header:
Authorization: Basic <username:password base64>
 - 
Body:
{ "updatedAt": "2024-03-01T18:58:47.878561013Z[GMT]", "appName": "string", "developer": "string", "credentialType": "CLIENT_CREDENTIALS | API_KEY", "clientId": "string", "apiKeyId": "string", "apis": [ { "id": "58baecsdd4", "action": "NONE | ADDED | REMOVED", "usagePlans": [ { "id": "3llq7e", "action": "NONE | ADDED | REMOVED" } ] } ] } 
Response
- 
HTTP status:
204 No Content - 
Body: vazio
 
A especificação de UpdateCredentialsRequest foi alterada. Foi incluído o campo customCredentials (opcional), para retorno de informações adicionais, como API KEY e CLIENT CREDENTIALS.
 | 
Revogar credenciais
POST /v1/revokeCredentials
Endpoint responsável por revogar (efetivamente desativar ou excluir) credenciais do app.
Request
- 
Header:
Authorization: Basic <username:password base64>
 - 
Body:
{ "appName": "string", "developer": "string", "credentialType": "CLIENT_CREDENTIALS | API_KEY", "clientId": string, "clientSecret": string, "apiKeyId": string, "apiKey": string } 
Response
- 
Status code:
204 No Content - 
Body: vazio
 
A especificação de RevokeCredentialsRequest foi alterada. Foi incluído o campo customCredentials (opcional), para retorno de informações adicionais, como API KEY e CLIENT CREDENTIALS.
 | 
Verificar disponibilidade
GET /v1/health
Endpoint de gerenciamento da aplicação.
Deve retornar 204 No Content caso a requisição seja realizada com sucesso.
Pode retornar outros status codes como 401,500 etc.
Request
- 
Header:
Authorization: Basic <username:password base64>
 - 
Body: vazio
 
Response
- 
Status code:
204 No Content - 
Body: vazio
 
Casos de erro
Caso o webhook retorne algum erro (status code 4xx ou 5xx), o formato esperado da mensagem é:
{
   "timestamp": date-time,
   "status": integer,
   "error": string,
   "messages": [
       string
   ],
   "path": string
}
Exemplo de implementação do webhook
AWS Lambda
Veja abaixo um exemplo de uma Lambda AWS, em python, que implementa todos os endpoints.
| 
O código abaixo é apenas uma referência. Você deve alterá-lo conforme suas necessidades de segurança ou regras de negócio. A única obrigatoriedade é seguir o contrato definido na especificação Open API.  | 
Para fazer o download do modelo, clique aqui.
Criando credenciais
Para criar credenciais, há dois métodos:
API Keys
As API Keys são geradas com o nome do app do Developer Portal e o e-mail do desenvolvedor que criou o app.
Veja o exemplo abaixo:
 def create_api_key(request_body):
    """Creates a new API Key and associates it with the requested Usage Plans. Return the API Key ID and value."""
    client = boto3.client("apigateway")
    app_slug = request_body.get("appSlug")
    developer = request_body.get("developer")
    apis = request_body.get("apis", [])
    try:
        api_key_response = client.create_api_key(
            name=create_credential_name(app_slug, developer),
            enabled=True,
            # tags={'string':'string'} can be used to distinct API Key created by the webhook
        )
        api_key_id = api_key_response["id"]
        api_key_value = api_key_response["value"]
        # Iterate over APIs in the request body
        for api_data in apis:
            # api_id = api_data.get('id') can be used to verify if API is still related to the Usage Plan
            usage_plans = api_data.get("usagePlans", [])
            # Iterate over usage plans for each API
            for usage_plan in usage_plans:
                usage_plan_id = usage_plan.get("id")
                # Associate API Key with Usage Plan
                client.create_usage_plan_key(
                    usagePlanId=usage_plan_id, keyId=api_key_id, keyType="API_KEY"
                )
        return {
            "statusCode": 200,
            "body": json.dumps(
                {
                    "credentialType": "API_KEY",
                    "apiKeyId": api_key_id,
                    "apiKey": api_key_value,
                    "customCredentials": {
                        "qaautomation-token-1": "qaautomationtoken1",
                        "qaautomation-token-2": "qaautomationtoken2",
                        "qaautomation-token-3": "qaautomationtoken3",
                        "qaautomation-token-4": "qaautomationtoken4",
                        "qaautomation-token-5": "qaautomationtoken5"
                    },
                }
            ),
        }
    except Exception as e:
        logger.error("create_api_key error: %s", str(e))
        return handle_error(str(e))
Esse método deve gerar uma nova chave no console da AWS:
E associá-la ao Usage Plans:
Client Credentials
As Client Credentials são configuradas pelo App Clients de um Cognito User Pool.
Veja o exemplo abaixo:
 def create_cognito_app_client(request_body):
    """Creates a Cognito app client and returns the client id and client secret."""
    cognito_client = boto3.client("cognito-idp")
    app_slug = request_body.get("appSlug")
    developer = request_body.get("developer")
    try:
        response = cognito_client.create_user_pool_client(
            UserPoolId=USER_POOL_ID,
            ClientName=create_credential_name(app_slug, developer),
            GenerateSecret=True,
            AllowedOAuthFlowsUserPoolClient=True,
            AllowedOAuthScopes=OAUTH_CUSTOM_SCOPES,
            AllowedOAuthFlows=["client_credentials"],
            SupportedIdentityProviders=["COGNITO"],
        )
        app_client_id = response["UserPoolClient"]["ClientId"]
        app_client_secret = response["UserPoolClient"]["ClientSecret"]
        return {
            "statusCode": 200,
            "body": json.dumps(
                {
                    "credentialType": "CLIENT_CREDENTIALS",
                    "clientId": app_client_id,
                    "clientSecret": app_client_secret,
                }
            ),
        }
    except Exception as e:
        logger.error("create_user_pool_client error: %s", str(e))
        return handle_error(str(e))
Esse método deverá criar um novo App Client:
Este app client terá as configurações necessárias para gerar Client Credentials:
Para autenticar as APIs usando tokens JWT, você deve ter o autorizador configurado no Gateway da AWS e vinculado ao pool de usuários do Cognito.
| Para que os desenvolvedores possam gerar os tokens, você precisará disponibilizar um endpoint fornecendo o client ID e o client secret gerados durante a criação do aplicativo. | 
No exemplo abaixo, é utilizado um endpoint do Cognito que gera o token de acordo com o grant-type:
Request
curl --location 'https://<your-cognito-domain>.auth.us-east-1.amazoncognito.com/token' \ --header 'Content-Type: application/x-www-form-urlencoded' \ --header 'Authorization: Basic MmhjZnVuN3Y4amRvYXA4NHNlNjQ0bWZxdm06dXQxcnVrZWs4amU3YXZiNjU4dGZwdTFwY2hrcDFpYzE2azhkbWJzYnJvcGl2amk4cWln' \ --data-urlencode 'grant_type=client_credentials'
Response
{
   "access_token": "eyJraWQiOiJnSlV3UTFOT1ZVbmVHRWJaWGNQK1J2TGdzaGNOOTM1MHZwUVJwbWRnXC9hYz0iLCJhbGciOiJSUzI1NiJ9.eyJzdWIiOiIyaGNmdW43djhqZG9hcDg0c2U2NDRtZnF2bSIsInRva2VuX3VzZSI6ImFjY2VzcyIsInNjb3BlIjoid2ViaG9vay1kZW1vLWlkZW50aWZpZXJcL2pzb24ucmVhZCIsImF1dGhfdGltZSI6MTcwOTMyMDk0NCwiaXNzIjoiaHR0cHM6XC9cL2NvZ25pdG8taWRwLnVzLWVhc3QtMS5hbWF6b25hd3MuY29tXC91cy1lYXN0LTFfZVA2aVZ5UDhaIiwiZXhwIjoxNzA5MzI0NTQ0LCJpYXQiOjE3MDkzMjA5NDQsInZlcnNpb24iOjIsImp0aSI6IjFiZjcyMGQ0LTQ3NjUtNGU1Zi1hNDU1LTg4NDg0YTQ5MzFlNyIsImNsaWVudF9pZCI6IjJoY2Z1bjd2OGpkb2FwODRzZTY0NG1mcXZtIn0.MQlT8YXAkXEmtLiFV_K7pq6aEylwEo1FrAx1At3PeFHkZ82lbuxXcHvVU8CFUfhURAXBqhTRR-KTT1LpBj6i_JUUhr_2obwVgZfKn1n94pfRw0tny8S5g88vuhuqNXn4CypnwrtGzoyYgV9liXykMX-80Y6ILZgtBcaFaBwpEsShv9Q9Q1S-XwQcQSCG0NF4-LF-bFx_KW3ZA3kV5IVVP0XpupYiP7My346kQUqCYboEeaoTDbEz_HqPTI6-r9Wnud7FvrXzl6YT0fhU6SHhx5QeI-zARemrI561Xf5cKkljuYSOWkSBRTADV-pKMj--X6WiBRZmDPN2f-0ziwAQpw",
   "expires_in": 3600,
   "token_type": "Bearer"
}
Revogando credenciais
API Keys
Veja o exemplo abaixo:
 def delete_api_key(request_body):
    """Deletes an API key."""
    client = boto3.client("apigateway")
    try:
        current_credential_type = request_body.get("credentialType")
        validate_credential_type_is_supported(current_credential_type)
        api_key_id = request_body.get("apiKeyId")
        if api_key_id is not None:
            client.delete_api_key(apiKey=api_key_id)
    except client.exceptions.NotFoundException:
        pass
    except Exception as e:
        logger.error("delete_api_key error: %s", str(e))
        return handle_error(str(e))
    return {"statusCode": 204}
Este método irá excluir a API Key do console da AWS.
Client Credentials
Veja o exemplo abaixo:
 def delete_cognito_app_client(request_body):
    """Deletes a Cognito app client."""
    cognito_client = boto3.client("cognito-idp")
    try:
        current_credential_type = request_body.get("credentialType")
        validate_credential_type_is_supported(current_credential_type)
        app_client_id = request_body.get("clientId")
        cognito_client.delete_user_pool_client(
            UserPoolId=USER_POOL_ID, ClientId=app_client_id
        )
    except cognito_client.exceptions.ResourceNotFoundException:
        pass
    except Exception as e:
        logger.error("delete_user_pool_client error: %s", str(e))
        return handle_error(str(e))
    return {"statusCode": 204}
Este método irá excluir o app client da console da AWS.
Share your suggestions with us!
          Click here and then [+ Submit idea]