Webhook
Aquí sigue un resumen del flujo de comunicación entre Developer Portal y webhook durante la solicitud de credenciales:
-
Desarrollador se registra en el Developer Portal.
-
Desarrollador va al menú Apps y crea una nueva app AWS (apps del API Manager Sensedia no utilizan webhook).
-
Sistema Developer Portal hace una solicitud HTTP al webhook, pasando la información de la app AWS del desarrollador.
-
Webhook, en su infraestructura, recibe la solicitud, crea las credenciales y las devuelve en la misma solicitud HTTP.
-
Sistema Developer Portal recibe la respuesta, guarda las credenciales en la base de datos y proporciona acceso al desarrollador.
Especificación
Es su responsabilidad implementar el webhook en su infraestructura, pero puede consultar un ejemplo de implementación. |
Especificación de Open API
Para crear el webhook, deberá implementar este Contrato de Open API.
La especificación ha sido modificada. Se ha agregado el campo customCredentials (opcional), que puede utilizarse con API KEY y CLIENT CREDENTIALS.
|
Endpoints
A continuación, vea los endpoints que deberá implementar y los detalles de solicitud y respuesta de cada uno de ellos.
Acción | Endpoint |
---|---|
Crear credenciales |
POST /v1/createCredentials |
Actualizar credenciales |
POST /v1/updateCredentials |
Revocar credenciales |
POST /v1/revokeCredentials |
Verificar disponibilidad |
GET /v1/health |
Autenticación
Todos los endpoints utilizarán autenticación básica.
Recibirá el header Authorization: Basic <username:password base64>
y deberá validarlo de la forma que desee.
Crear credenciales
POST /v1/createCredentials
Endpoint responsable de crear y devolver las credenciales de la 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 }
La respuesta puede devolver tanto una API Key como Client Credentials.
Para el credentialType=API_KEY
, se deben devolver los campos apiKeyId
y apiKey
.
Para el credentialType=CLIENT_CREDENTIALS
, se deben devolver los campos clientId
y clientSecret
.
La especificación de CreateCredentialsResponse ha sido modificada. Se ha incluido el campo customCredentials (opcional), para devolver información adicional, como API KEY y CLIENT CREDENTIALS.
|
Actualizar credenciales
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: vacío
La especificación de UpdateCredentialsRequest ha sido modificada. Se ha incluido el campo customCredentials (opcional), para devolver información adicional, como API KEY y CLIENT CREDENTIALS.
|
Revocar credenciales
POST /v1/revokeCredentials
Endpoint responsable de revocar (efectivamente desactivar o eliminar) credenciales de la 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: vacío
La especificación de RevokeCredentialsRequest ha sido modificada. Se ha incluido el campo customCredentials (opcional), para devolver información adicional, como API KEY y CLIENT CREDENTIALS.
|
Verificar disponibilidad
GET /v1/health
Endpoint de gestión de la aplicación.
Debe retornar 204 No Content
si la solicitud se realiza con éxito.
Puede retornar otros códigos de estado como 401
, 500
etc.
Request
-
Header:
Authorization: Basic <username:password base64>
-
Body: vacío
Response
-
Status code:
204 No Content
-
Body: vacío
Casos de error
Si el webhook devuelve un error (código de estado 4xx
o 5xx
), el formato esperado del mensaje es:
{ "timestamp": date-time, "status": integer, "error": string, "messages": [ string ], "path": string }
Ejemplo de implementación del webhook
AWS Lambda
A continuación, vea un ejemplo de una Lambda AWS, en python, que implementa todos los endpoints.
El código a continuación es solo una referencia.
Debe modificarlo según sus necesidades de seguridad o reglas de negocio. La única obligación es seguir el contrato definido en la especificación de Open API. |
Para descargar el modelo, haga clic aquí.
Creando credenciales
Para crear credenciales, hay dos métodos:
API Keys
Las API Keys se generan con el nombre de la app del Developer Portal y el correo electrónico del desarrollador que creó la app.
Vea el ejemplo a continuación:
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))
Este método debe generar una nueva clave en la consola de AWS:
Y asociarla a los Usage Plans:
Client Credentials
Las Client Credentials se configuran por el App Clients de un Cognito User Pool.
Vea el ejemplo a continuación:
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))
Este método deberá crear un nuevo App Client:
Este app client tendrá las configuraciones necesarias para generar Client Credentials:
Para autenticar las APIs usando tokens JWT, usted debe tener el autorizador configurado en el Gateway de AWS y vinculado al pool de usuarios de Cognito.
Para que los desarrolladores puedan generar los tokens, necesitará proporcionar un endpoint que entregue el client ID y el client secret generados durante la creación de la aplicación. |
En el ejemplo a continuación, se utiliza un endpoint de Cognito que genera el token según el 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" }
Revocando credenciales
API Keys
Vea el ejemplo a continuación:
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 eliminará la API Key de la consola de AWS.
Client Credentials
Vea el ejemplo a continuación:
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 eliminará el app client de la consola de AWS.
Share your suggestions with us!
Click here and then [+ Submit idea]