Skip to content

Instantly share code, notes, and snippets.

What would you like to do?
django-boto3-cognito: AWS' Cognito Developer Authenticated Identities Authflow using Django/Python/Boto3 (For building stand-alone clients)
__author__ = 'dkarchmer'
This script emulates a stand-alone Python based client. It relies on Boto3 to access AWS, but
requires your Django server to have an API for your user to access Cognito based credentials
Because of Cognito, the client (this script) will only get temporary AWS credentials associated
to your user and only your user, and based on whatever you configure your AIM Policy to be.
Most Cognito examples demonstrate how to use Cognito for Mobile Apps, so this scripts demonstrate
how to create a stand-alone Python script but operating similarly to these apps.
import json
import requests
import logging
import boto3
from boto3.session import Session
AWS_REGION = 'us-east-1'
AV_API_PREFIX = 'api/v1'
logger = logging.getLogger(__name__)
class Connection(object):
token = None
def __init__(self, domain=None):
if domain:
self.domain = domain
def _get_url(self, api):
url = '{0}/{1}/{2}'.format(self.domain, AV_API_PREFIX, api)
logger.debug('Calling: ' + url)
return url
def _get_header(self, use_token):
if use_token:
if not self.token:
raise('No Token')
authorization_str = 'token %s' % self.token
headers = {'content-type': 'application/json',
'Authorization': authorization_str}
headers = {'Content-Type': 'application/json'}
return headers
def get(self, api, use_token):
url = self._get_url(api)
headers = self._get_header(use_token)
r = requests.get(url, headers=headers)
return r
def login(self, password, email):
data = { 'email': email, 'password': password }
api = 'auth/login'
r =, data=data, use_token=False)
if r.status_code == 200:
content = json.loads(r.content.decode())
self.token = content['token']
self.username = content['username']'Welcome @{0} (token: {1})'.format(self.username, self.token))
return True
logger.error('Login failed: ' + str(r.status_code) + ' ' + r.content.decode())
return False
def logout(self):
api = 'auth/logout'
r =, use_token=True)
if r.status_code == 204:'Goodbye @{0}'.format(self.username))
self.username = None
self.token = None
logger.error('Logout failed: ' + str(r.status_code) + ' ' + r.content.decode())
if __name__ == '__main__':
# Test
# Logger Format
from logging import StreamHandler, Formatter
FORMAT = '[%(asctime)-15s] %(levelname)-6s %(message)s'
DATE_FORMAT = '%d/%b/%Y %H:%M:%S'
formatter = Formatter(fmt=FORMAT, datefmt=DATE_FORMAT)
handler = StreamHandler()
c = Connection('')
c.login(email='', password='user1')
r = c.get(api='auth/aws', use_token=True)
if r.status_code == 200:
content = json.loads(r.content.decode())
# Given the resp from the server, with an IdentityId and a Token, the client can directly
# get credentials from Cognito, which should be based on a given IAM Role
# (One that only allows access to wahtever services you want the client script to access. e.g. S3 uploads)
client = boto3.client('cognito-identity', AWS_REGION)
resp = client.get_credentials_for_identity(IdentityId=content['IdentityId'],
Logins={'': content['Token']})
# The resp contains the actual temporary AWS secret/access codes and a session token, to be
# used with the rest of the AWS APIs
secretKey = resp['Credentials']['SecretKey']
accessKey = resp['Credentials']['AccessKeyId']
sessionToken = resp['Credentials']['SessionToken']
# Now you can use Boto3 like you would if you were using your own secret keys
# what you will see in any Boto3 example on the web
session = Session(aws_access_key_id=accessKey,
s3_resource = session.resource('s3')
bucket = s3_resource.Bucket('bucket-with-role-permision')
print('\n' + str(bucket))
for key in bucket.objects.all():"-------------")
__author__ = 'dkarchmer'
This file demonstrates how to create a Django Rest Framework (DRF) APIView based API to provide
user access to AWS credentials via Cognito (In the script above, this is defined as
NOTE: This is NOT intended to be fully working code. It may not, for example, contain all required imports
It also does not explain how to hook this with Django and DRF. It assumes you know how to do so
But the Class and associated functions are in fact fully functional.
import logging
import boto3
import botocore
from rest_framework.response import Response
from rest_framework.views import APIView
AWS_REGION = 'us-east-1
# Get an instance of a logger
logger = logging.getLogger(__name__)
# Assumes a cognito identity pool has been created.
IDENTITY_POOL_ID = 'us-east-1:XXXXXXXXXX-1234-1234-1234-YYYYYYYYY'
# Change based on what you entered on the AWS Cognito Dashboard (Custom tab)
def get_aws_open_id_token(username):
client = boto3.client('cognito-identity', AWS_REGION)
# This is what should be done by the Server (after proper login).
# It requires the Role to have access to cognito
# Given a valid user (per server's authentication), the API should return the Cognito Resp
# directly to the client
# See'Requesting open_id from Cognito for: {0}'.format(username))
resp = client.get_open_id_token_for_developer_identity(
)"Identity ID: {0}".format(resp['IdentityId']))"Request ID : {0}".format((resp['ResponseMetadata']['RequestId'])))
except botocore.exceptions.ClientError as e:
resp = None
return resp
class APICognitoViewSet(APIView):
GET IdentityId/Token that can be used by client to get Temporary AWS credentials
This is the class that services the /auth/aws GET API in the script above
def get(self, request, format=None):
Update IdentityID and Token from Cognito
if request.user.is_anonymous():
# User most login before they can get a token
# This not only ensures the user has registered, and has an account
# but that the account is active
return Response('User not recognized.', status=status.HTTP_403_FORBIDDEN)
data_dic = {}
resp = get_aws_open_id_token(request.user.username)
if resp:
mystatus = resp['ResponseMetadata']['HTTPStatusCode']
data_dic['IdentityId'] = resp['IdentityId']
data_dic['Token'] = resp['Token']
logger.error('Something wrong with Cognito call')
return Response(data_dic, status=mystatus)
urlpatterns = patterns('',
url(r'^auth/aws', APICognitoViewSet.as_view(), name='api-cognito'),
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment