Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cognito client crendetials flow #1528

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 63 additions & 0 deletions content/en/user-guide/aws/cognito/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,69 @@ Ensuring this match is crucial for the proper functioning of the authentication
{"access_token": "eyJ0eXAi…lKaHx44Q", "expires_in": 86400, "token_type": "Bearer", "refresh_token": "e3f08304", "id_token": "eyJ0eXAi…ADTXv5mA"}
```

### Client credentials grant

The client credentials grant is designed for machine-to-machine (M2M) communication.
In contrast, the authorization code and implicit grants provide tokens to authenticated human users.
The client credentials grant allows for scope-based authorization from a non-interactive system to an API.
Your app can directly request client credentials from the token endpoint to receive an access token.

To request the token from LocalStack the correct URL is `http://cognito-idp.localhost.localstack-test.cloud:4566/_aws/cognito-idp/oauth2/token`.
drauedo marked this conversation as resolved.
Show resolved Hide resolved
In case that there is more than one user pool, LocalStack detects the right one by inspecting the `clientId` of the requests.

Here is an example on how to set it up:

```sh
#Create user pool.
export pool_id=$(awslocal cognito-idp create-user-pool --pool-name test --username-configuration "CaseSensitive=False" | jq -rc ".UserPool.Id")

#Create client user pool with a client.
export client_id=$(awslocal cognito-idp create-user-pool-client --user-pool-id $pool_id --client-name test-client --generate-secret | jq -rc ".UserPoolClient.ClientId")

#Retrieve secret.
export client_secret=$(awslocal cognito-idp describe-user-pool-client --user-pool-id $pool_id --client-id $client_id | jq -r '.UserPoolClient.ClientSecret')
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Take into account that if the LocalStack user has setup LocalStack as a separate container to their system, they won't be able to get the variables exported here.

What we did was have a local.env file in which the variables were defined (e.g. user pool id). Then pass that to the LocalStack container in the Environment section. Then, in the app use that same local.env to have the same environment information in both containers.

When creating the pool and so on, it would be cool to remind people that you can setup the custom_id, instead of letting LocalStack generate it.


#Create resource server
awslocal cognito-idp create-resource-server \
--user-pool-id $pool_id \
--identifier "api-client-organizations" \
--name "vitalera API Clients Organizations Resource Server" \
drauedo marked this conversation as resolved.
Show resolved Hide resolved
--scopes '[{"ScopeName":"read","ScopeDescription":"Read access to Organizations"}]'

```

Then you could retrieve the token from your application like this:

```python
import requests, os
from requests.auth import HTTPBasicAuth

def get_access_token_with_secret():
client_id = os.environ['client_id']
client_secret = os.environ['client_secret']
scope = 'api-client-organizations/read'
url = 'http://cognito-idp.localhost.localstack.cloud:4566/_aws/cognito-idp/oauth2/token'


headers = {
'Content-Type' : 'application/x-www-form-urlencoded'
}

auth = HTTPBasicAuth(client_id,client_secret)

payload = {
'grant_type': 'client_credentials',
'client_id':client_id,
'scope':scope
}
response = requests.post(url,headers=headers,auth=auth,data=payload)

print(response.content)

if __name__ == "__main__":
get_access_token_with_secret()
```

Copy link

@usl-cto usl-cto Oct 30, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that it would be better to have a sample code in which the Cognito client is created in the Python code, from which you could extract the client ID and secret, and then do the token request. The sh would only need to create the pool.

I say this because that may be a more common scenario, normally you would create as many apps as M2M users are in your system.

## Serverless and Cognito

Furthermore, you have the option to combine Cognito and LocalStack seamlessly with the [Serverless framework](https://www.serverless.com/).
Expand Down