I'm creating an api service ("My Api") where the end users are other apis ("Client"). This is my first application where the Client is not an actual person, so I want to make sure I'm going through the authentication flow correctly.
I'm using AWS Cognito and have based the authentication flow off the "Client credentials grant" section of this post.
The flow I have right now is:
curl -X POST \
https://[DOMAIN_NAME].auth.[REGION].amazoncognito.com/oauth2/token \
-H 'Content-Type: application/x-www-form-urlencoded' \
-H 'authorization: Basic BASE64(client_id:client_secret)' \
-d 'grant_type=client_credentials&scope=[SCOPE]'
It seems strange that I have to create an app client on AWS Cognito for each Client. Is that normal when you're authenticating using client credentials instead of an authorization code?
If that's the case, can someone direct me to what the pricing is for each each app client? Is it in the "Users who sign in directly with their User Pool credentials or with social identity providers:" section on this page?
After some time to think about this, this is what I would do (preface: this is definitely not AWS/Banking level authentication). The code below is in postgres.
I would design the database schema to accommodate multiple tenants see this paper by Google for ideas. Each User (eg, employee of an Organization) will have a Cognito User which will be linked to the User.
CREATE TABLE organizations (
org_id uuid
);
CREATE TABLE users (
user_id uuid,
cognito_uid uuid,
org_id uuid REFERENCES organizations(org_id)
);
CREATE TABLE secret_stuffs (
secrets varchar
);
I would then create an api_keys table.
// We only want user to have two keys max
CREATE TYPE api_key_type AS ENUM (
'primary',
'secondary'
);
CREATE TABLE api_keys (
PRIMARY KEY (
user_id,
key_type
)
org_id uuid REFERENCES organizations(org_id),
user_id uuid REFERENCES users(user_id),
key_type api_key_type,
private_key varchar
);
// You'd probably want to create a composite index with user_id and private_key fields since we'll create a function that access both
I would lock down the api_keys
and secret_stuffs
table (ie, not grant access to any role) and create a SECURITY DEFINER
function that takes the user_id
and private_key
as inputs, checks that that row exists in your api_keys
table and returns whatever you need from the secret_stuffs
table.