{"id":1775,"date":"2020-09-18T11:55:48","date_gmt":"2020-09-18T09:55:48","guid":{"rendered":"https:\/\/blog.besharp.it\/?p=1775"},"modified":"2022-09-07T12:30:20","modified_gmt":"2022-09-07T10:30:20","slug":"setting-up-machine-to-machine-authentication-with-amazon-cognito","status":"publish","type":"post","link":"https:\/\/blog.besharp.it\/setting-up-machine-to-machine-authentication-with-amazon-cognito\/","title":{"rendered":"Setting up a machine-to-machine authentication system with Amazon Cognito"},"content":{"rendered":"\n
\n

More and more applications, both mobile and web, rely on managed services such as Amazon Cognito for user authentication and authorization. Cognito allows you to rapidly develop secure applications adhering to recognized security standards for authentication and authorization of end-users.\n<\/p>\n\n\n\n

Leveraging a fully managed service allows developers to stop worrying about the authentication flow and the user pool management, leaving them free to focus on what matters: the business logic of their products.\n<\/p>\n\n\n\n

However quite often we would like to federate with our application third-party service or another microservice.\n<\/p>\n\n\n\n

While Cognito is mainly used for user authentication flows, it can also be used to create a machine to machine authentication system.\n<\/p>\n\n\n\n

In this article we’ll describe how Cognito can be used to authenticate a client system that needs access to a set of sensitive APIs exposed by a service.\n\n<\/p>\n\n\n\n

However before deep diving into the description of the solution, it could be useful to describe the services involved.<\/p>\n\n\n\n

What is Amazon Cognito?<\/h2>\n\n\n\n

When you need to implement an authorization and authentication system on AWS, Amazon Cognito is your best choice.<\/p>\n\n\n\n

Amazon Cognito lets you add user sign-up, sign-in, and access control to your web and mobile apps quickly and easily, it scales to millions of users and supports sign-in with social identity providers, such as Facebook, Google, and Amazon, and enterprise identity providers via SAML 2.0.<\/p>\n\n\n\n

Furthermore Cognito also supports multi-factor authentication and encryption of data-at-rest and in-transit. Amazon Cognito is HIPAA eligible and PCI DSS, SOC, ISO\/IEC 27001, ISO\/IEC 27017, ISO\/IEC 27018, and ISO 9001 compliant.\n<\/p>\n\n\n\n

Let\u2019s move on to describe the main concepts of Cognito.<\/p>\n\n\n\n

Users are managed through two types of pools, which are at the heart of Amazon Cognito\u2019s operation: User Pools and Identity Pools.\n<\/p>\n\n\n\n

User Pool<\/h2>\n\n\n\n

A user pool is essentially a user directory that allows you to securely store your users\u2019 profile attributes. This is a convenient way to completely off-load user profile management, security, and availability. Among the operations which can be off-loaded, there is certainly the secure storage of user data, the verification of telephone numbers and\/or e-mail addresses, the management of the login system APIs, and the flow of registration, login, logout, and password reset.\n<\/p>\n\n\n\n

In addition, to using the Amazon Cognito-specific user APIs to authenticate users, Amazon Cognito user pools also support the OAuth 2.0 authentication protocol to authenticate users or applications.\n<\/p>\n\n\n\n

User pools are a fundamental component of any authentication system based on Amazon Cognito, and we will leverage this component to build our machine to machine authentication system.\n<\/p>\n\n\n\n

Identity Pool<\/h2>\n\n\n\n

We are not going to use Identity Pools for this specific scenario, but it could be useful to describe them briefly.\n<\/p>\n\n\n\n

Identity pools are used by Cognito Identity to keep the application\u2019s federated identities organized. An identity pool associates federated identities from external identity providers with a unique specific user identifier. Identity pools do not store user profiles, but only their unique ids, which are generated and managed by Cognito. Cognito Identity pools assign users a set of temporary IAM credentials with limited privileges. Users or client applications can use those credentials to access AWS resources. Authorizations rules for each user are controlled through customizable AWS IAM roles and policies. It is also possible to define rules to match Users with the desired role. <\/p>\n\n\n\n

Now that we\u2019ve defined all the fundamental concepts we can move on to the central part of our article.<\/p>\n\n\n\n

System to system Authentication Flow<\/h2>\n\n\n\n

Let’s start by defining the authentication flow that we will configure in the next steps.<\/p>\n<\/div><\/div>\n\n\n

\n
\"\"<\/figure><\/div>\n\n\n

As described in the OAuth 2.0 specifications, we can authenticate a client that presents a valid Client Id and Client Secret to our Identity Provider. \n<\/p>\n\n\n\n

As you can see from the image above, a generic client can call AWS Cognito APIs with the previously shared Client Id and Client Secret. If the two parameters are valid, AWS Cognito returns an Access Token. Now the application can call your services passing the retrieved Token. <\/p>\n\n\n\n

What your services have to do now, is to validate it as described by the OAuth 2.0 specification. In this step you need to:\n<\/p>\n\n\n\n

  1. Validate that the received JWT has a valid format.<\/li>
  2. Validate the JWT Signature.<\/li>
  3. Verify all the Claims.<\/li><\/ol>\n\n\n\n

    With the authentication flow in mind, let’s go on to configure it inside your AWS Account.\n<\/p>\n\n\n\n

    Hands-on!<\/h1>\n\n\n\n

    Now that you are aware of the different Amazon Cognito components, we can start with the project. First of all, a basic user group needs to be created from the AWS console. To do so it\u2019s possible to choose an explicative name and keep all the default settings by clicking the \u201cReview defaults\u201d button.\n<\/p>\n\n\n\n

    \"create<\/figure>\n\n\n\n

    At this point we can start exploring the numerous options provided by our new user pool, tweaking the ones needed for our project.\n<\/p>\n\n\n\n

    The server that will handle the authorized requests can be specified in the resource server page of the Cognito console<\/p>\n\n\n\n

    Here you\u2019ll be able to determine the unique URL of the server exposing the APIs you need to protect. Moreover, a set of scopes can be listed in this page to discriminate, for example, various levels of access to your service.\n<\/p>\n\n\n\n

    \"set<\/figure>\n\n\n\n

    Now that the resource server has been configured, we can follow up with the settings of the app clients.\n<\/p>\n\n\n\n

    In this page it\u2019s possible to define a new client, for example, a new web-app that needs to consume the set of APIs you want to protect. \n<\/p>\n\n\n

    \n
    \"app<\/figure><\/div>\n\n\n

    Here you can specify the name of the new client and the expiration of the security tokens used in the authorization process. Due to the client credentials grant type specifications, ID tokens and refresh tokens are not used, hence only the access token\u2019s expiration is important. <\/p>\n\n\n\n

    When these details are submitted, Cognito will prompt us with an app client id and an app client secret. Although the client id is intended as a public identifier of apps, it\u2019s important that you never share either the id or the secret for security reasons.<\/p>\n\n\n\n

    These two tokens need to be encrypted and stored by each of the registered applications to request access tokens to the Cognito user pool. They are essentially the username and password of the system-to-system authorization.<\/p>\n\n\n\n

    Your app is now successfully registered and it\u2019s possible to edit the authorization options you want to enable for its users from the <\/span>app client settings<\/b> page.<\/span><\/p>\n\n\n\n

    In this form, in fact, you\u2019ll be able to choose the client credentials OAuth flow as the single method allowed to request access tokens. From this page, you\u2019re also able to define which scopes can be used by each app client, to get rid of the possibility to request APIs that are not meant to be called from a specific client.\n<\/p>\n\n\n\n

    \"scope<\/figure>\n\n\n\n

    As a final step on the cognito console, a domain name needs to be chosen. In fact, on this page, we\u2019ll choose (if available) where the applications will send the access token requests.\n<\/p>\n\n\n\n

    \"choose<\/figure>\n\n\n\n

    Cognito is now ready to prompt to you tons of access tokens!<\/p>\n\n\n\n

    import requests\n \nTOKEN_ENDPOINT = 'https:\/\/system-to-system.auth.eu-west-1.amazoncognito.com\/oauth2\/token'\n \nbody = {\n    'grant_type': 'client_credentials',\n    'client_id': CLIENT_ID,\n    'client_secret': CLIENT_SECRET,\n    'scope': 'https:\/\/my-api-server.org\/api.readwrite'\n}\n \nresponse = requests.post(TOKEN_ENDPOINT, data=body)\nprint(response.text)\n \n<\/pre>\n\n\n\n

    As you can see from the snippet above, the retrieval of the access token is a fairly simple HTTP POST request that needs in its body few simple parameters seen before. The token endpoint is built from the newly created domain name.\n<\/p>\n\n\n\n

    The access token we just received is now ready to be shipped within an API call to the resource server. The latter, then, must be able to decode it and validate it against a set of public signature keys exposed by cognito.\n<\/p>\n\n\n\n

    import functools\nimport json\nimport jwt\nimport urllib.request\ndef is_valid_token(scope) -> bool:\n    def wrapped(func):\n        @functools.wraps(func)\n        def wrapper(access_token):\n            public_keys = get_well_known_jwk(REGION, USER_POOL_ID)\n            kid = jwt.get_unverified_header(access_token)['kid']\n            key = public_keys[kid]\n            payload = jwt.decode(access_token, key=key, algorithms=['RS256'])\n            if payload['client_id'] != CLIENT_ID:\n                print('Wrong client_id')\n                raise Exception('Wrong client id')\n            if payload['scope'] != scope:\n                print('Wrong scope')\n                raise Exception('Wrong scope')\n            return func(access_token)\n        return wrapper\n    return wrapped\ndef get_well_known_jwk(region: str, user_pool_id: str) -> dict:\n    jwk_url = f\"https:\/\/cognito-idp.{region}.amazonaws.com\/{user_pool_id}\/.well-known\/jwks.json\"\n    with urllib.request.urlopen(jwk_url) as url:\n        jwks = json.loads(url.read().decode())\n    public_keys = {}\n    for jwk in jwks['keys']:\n        kid = jwk['kid']\n        public_keys[kid] = jwt.algorithms.RSAAlgorithm.from_jwk(json.dumps(jwk))\n    return public_keys\n@is_valid_token(scope = 'https:\/\/my-api-server.org\/api.write')\ndef api(access_token):\n    resp = {\n        \"status_code\": 200,\n        \"body\": \"This is your body.\"\n    }\n    print(json.dumps(resp))\n<\/pre>\n\n\n\n

    You can now test the solution and authenticate other services in your application.<\/p>\n\n\n\n

    That\u2019s all for today! In this article, we explained how to build a secure, reliable, and fully managed machine to machine authentication system leveraging Amazon Cognito and Cognito User Pools.<\/p>\n\n\n\n

    Feel free to contact us and comment below to ask questions or just to add your thoughts on the subject.<\/p>\n\n\n\n

    Stay tuned for the next article and see you in 14 days<\/strong> on #Proud2beCloud<\/strong>!<\/p>\n","protected":false},"excerpt":{"rendered":"

    More and more applications, both mobile and web, rely on managed services such as Amazon Cognito for user authentication and […]<\/p>\n","protected":false},"author":9,"featured_media":1769,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[472],"tags":[326],"yoast_head":"\nSetting up a machine-to-machine authentication system with Amazon Cognito - Proud2beCloud Blog<\/title>\n<meta name=\"description\" content=\"how to build a secure, reliable, and fully managed machine to machine authentication system leveraging Amazon Cognito and Cognito User Pools.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/blog.besharp.it\/setting-up-machine-to-machine-authentication-with-amazon-cognito\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Machine-to-machine authentication with Amazon Cognito\" \/>\n<meta property=\"og:description\" content=\"Building a secure, reliable, and fully managed machine to machine authentication system using Amazon Cognito.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/blog.besharp.it\/setting-up-machine-to-machine-authentication-with-amazon-cognito\/\" \/>\n<meta property=\"og:site_name\" content=\"Proud2beCloud Blog\" \/>\n<meta property=\"article:published_time\" content=\"2020-09-18T09:55:48+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2022-09-07T10:30:20+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/blog.besharp.it\/wp-content\/uploads\/2020\/09\/facebook-link-image-1.png\" \/>\n<meta name=\"author\" content=\"Matteo Moroni\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:title\" content=\"Machine-to-machine authentication with Amazon Cognito\" \/>\n<meta name=\"twitter:description\" content=\"Building a secure, reliable, and fully managed machine to machine authentication system using Amazon Cognito.\" \/>\n<meta name=\"twitter:image\" content=\"https:\/\/blog.besharp.it\/wp-content\/uploads\/2020\/09\/twitter-shared-link-1.png\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Matteo Moroni\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"8 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\/\/blog.besharp.it\/setting-up-machine-to-machine-authentication-with-amazon-cognito\/\",\"url\":\"https:\/\/blog.besharp.it\/setting-up-machine-to-machine-authentication-with-amazon-cognito\/\",\"name\":\"Setting up a machine-to-machine authentication system with Amazon Cognito - Proud2beCloud Blog\",\"isPartOf\":{\"@id\":\"https:\/\/blog.besharp.it\/#website\"},\"datePublished\":\"2020-09-18T09:55:48+00:00\",\"dateModified\":\"2022-09-07T10:30:20+00:00\",\"author\":{\"@id\":\"https:\/\/blog.besharp.it\/#\/schema\/person\/0b3e69eb2dcb125d58476b906ec1c7bc\"},\"description\":\"how to build a secure, reliable, and fully managed machine to machine authentication system leveraging Amazon Cognito and Cognito User Pools.\",\"breadcrumb\":{\"@id\":\"https:\/\/blog.besharp.it\/setting-up-machine-to-machine-authentication-with-amazon-cognito\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/blog.besharp.it\/setting-up-machine-to-machine-authentication-with-amazon-cognito\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/blog.besharp.it\/setting-up-machine-to-machine-authentication-with-amazon-cognito\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/blog.besharp.it\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Setting up a machine-to-machine authentication system with Amazon Cognito\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/blog.besharp.it\/#website\",\"url\":\"https:\/\/blog.besharp.it\/\",\"name\":\"Proud2beCloud Blog\",\"description\":\"il blog di beSharp\",\"alternateName\":\"Proud2beCloud Blog\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/blog.besharp.it\/?s={search_term_string}\"},\"query-input\":\"required name=search_term_string\"}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\/\/blog.besharp.it\/#\/schema\/person\/0b3e69eb2dcb125d58476b906ec1c7bc\",\"name\":\"Matteo Moroni\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/blog.besharp.it\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/acad790b9bb4c6d62e076ecdc1debb35?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/acad790b9bb4c6d62e076ecdc1debb35?s=96&d=mm&r=g\",\"caption\":\"Matteo Moroni\"},\"description\":\"DevOps e Solution Architect di beSharp, mi occupo di sviluppare soluzioni Saas, Data Analysis, HPC e di progettare architetture non convenzionali a complessit\u00e0 divergente. Appassionato di informatica e fisica, da sempre lavoro nella prima e ho un PhD nella seconda. Parlare di tutto ci\u00f2 che \u00e8 tecnico e nerd mi rende felice!\",\"url\":\"https:\/\/blog.besharp.it\/author\/matteo-moroni\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Setting up a machine-to-machine authentication system with Amazon Cognito - Proud2beCloud Blog","description":"how to build a secure, reliable, and fully managed machine to machine authentication system leveraging Amazon Cognito and Cognito User Pools.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/blog.besharp.it\/setting-up-machine-to-machine-authentication-with-amazon-cognito\/","og_locale":"en_US","og_type":"article","og_title":"Machine-to-machine authentication with Amazon Cognito","og_description":"Building a secure, reliable, and fully managed machine to machine authentication system using Amazon Cognito.","og_url":"https:\/\/blog.besharp.it\/setting-up-machine-to-machine-authentication-with-amazon-cognito\/","og_site_name":"Proud2beCloud Blog","article_published_time":"2020-09-18T09:55:48+00:00","article_modified_time":"2022-09-07T10:30:20+00:00","og_image":[{"url":"https:\/\/blog.besharp.it\/wp-content\/uploads\/2020\/09\/facebook-link-image-1.png"}],"author":"Matteo Moroni","twitter_card":"summary_large_image","twitter_title":"Machine-to-machine authentication with Amazon Cognito","twitter_description":"Building a secure, reliable, and fully managed machine to machine authentication system using Amazon Cognito.","twitter_image":"https:\/\/blog.besharp.it\/wp-content\/uploads\/2020\/09\/twitter-shared-link-1.png","twitter_misc":{"Written by":"Matteo Moroni","Est. reading time":"8 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/blog.besharp.it\/setting-up-machine-to-machine-authentication-with-amazon-cognito\/","url":"https:\/\/blog.besharp.it\/setting-up-machine-to-machine-authentication-with-amazon-cognito\/","name":"Setting up a machine-to-machine authentication system with Amazon Cognito - Proud2beCloud Blog","isPartOf":{"@id":"https:\/\/blog.besharp.it\/#website"},"datePublished":"2020-09-18T09:55:48+00:00","dateModified":"2022-09-07T10:30:20+00:00","author":{"@id":"https:\/\/blog.besharp.it\/#\/schema\/person\/0b3e69eb2dcb125d58476b906ec1c7bc"},"description":"how to build a secure, reliable, and fully managed machine to machine authentication system leveraging Amazon Cognito and Cognito User Pools.","breadcrumb":{"@id":"https:\/\/blog.besharp.it\/setting-up-machine-to-machine-authentication-with-amazon-cognito\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/blog.besharp.it\/setting-up-machine-to-machine-authentication-with-amazon-cognito\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/blog.besharp.it\/setting-up-machine-to-machine-authentication-with-amazon-cognito\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/blog.besharp.it\/"},{"@type":"ListItem","position":2,"name":"Setting up a machine-to-machine authentication system with Amazon Cognito"}]},{"@type":"WebSite","@id":"https:\/\/blog.besharp.it\/#website","url":"https:\/\/blog.besharp.it\/","name":"Proud2beCloud Blog","description":"il blog di beSharp","alternateName":"Proud2beCloud Blog","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/blog.besharp.it\/?s={search_term_string}"},"query-input":"required name=search_term_string"}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/blog.besharp.it\/#\/schema\/person\/0b3e69eb2dcb125d58476b906ec1c7bc","name":"Matteo Moroni","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/blog.besharp.it\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/acad790b9bb4c6d62e076ecdc1debb35?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/acad790b9bb4c6d62e076ecdc1debb35?s=96&d=mm&r=g","caption":"Matteo Moroni"},"description":"DevOps e Solution Architect di beSharp, mi occupo di sviluppare soluzioni Saas, Data Analysis, HPC e di progettare architetture non convenzionali a complessit\u00e0 divergente. Appassionato di informatica e fisica, da sempre lavoro nella prima e ho un PhD nella seconda. Parlare di tutto ci\u00f2 che \u00e8 tecnico e nerd mi rende felice!","url":"https:\/\/blog.besharp.it\/author\/matteo-moroni\/"}]}},"_links":{"self":[{"href":"https:\/\/blog.besharp.it\/wp-json\/wp\/v2\/posts\/1775"}],"collection":[{"href":"https:\/\/blog.besharp.it\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.besharp.it\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.besharp.it\/wp-json\/wp\/v2\/users\/9"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.besharp.it\/wp-json\/wp\/v2\/comments?post=1775"}],"version-history":[{"count":0,"href":"https:\/\/blog.besharp.it\/wp-json\/wp\/v2\/posts\/1775\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blog.besharp.it\/wp-json\/wp\/v2\/media\/1769"}],"wp:attachment":[{"href":"https:\/\/blog.besharp.it\/wp-json\/wp\/v2\/media?parent=1775"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.besharp.it\/wp-json\/wp\/v2\/categories?post=1775"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.besharp.it\/wp-json\/wp\/v2\/tags?post=1775"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}