<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Ernest Chiang</title>
    <description>The latest articles on DEV Community by Ernest Chiang (@dwchiang).</description>
    <link>https://dev.to/dwchiang</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F409449%2Fc83067d8-fd3a-4fe4-8319-d3f551286127.jpeg</url>
      <title>DEV Community: Ernest Chiang</title>
      <link>https://dev.to/dwchiang</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/dwchiang"/>
    <language>en</language>
    <item>
      <title>How to Deploy Static Website with OAuth 2.0 Authorization, CloudFront CDN in 20 Minutes?</title>
      <dc:creator>Ernest Chiang</dc:creator>
      <pubDate>Tue, 04 May 2021 10:51:47 +0000</pubDate>
      <link>https://dev.to/dwchiang/using-aws-cdk-to-deploy-static-website-ft-oauth-2-0-authorization-code-36h6</link>
      <guid>https://dev.to/dwchiang/using-aws-cdk-to-deploy-static-website-ft-oauth-2-0-authorization-code-36h6</guid>
      <description>&lt;p&gt;&lt;em&gt;(Illustration: Afternoon-tea with Grilled Halloumi Cheese. Not-so-related to this article, I know XDD. When writing such a long post, you know :p Image source: by Ernest, in London.)&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  0. Origin
&lt;/h2&gt;

&lt;p&gt;This month &lt;a href="https://twitter.com/pahudnet" rel="noopener noreferrer"&gt;Pahud&lt;/a&gt; invited us - a group of AWS Hero and AWS Builders to use &lt;a href="https://www.ernestchiang.com/en/notes/aws/cdk/" rel="noopener noreferrer"&gt;AWS CDK&lt;/a&gt; to code around CloudFront Extensions (&lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/lambda-edge.html" rel="noopener noreferrer"&gt;CloudFront Lambda@Edge&lt;/a&gt;). From my long todo list, I found a topic related to OAuth 2.0 that I have always wanted to do. It's a perfect timing to try and see how to implement a CloudFront Extension solution in &lt;a href="https://www.ernestchiang.com/en/notes/aws/cdk/" rel="noopener noreferrer"&gt;AWS CDK&lt;/a&gt; (Cloud Development Kit) with &lt;code&gt;.env&lt;/code&gt; environment variable settings, so that you can easily set your favorite IdP (Identity Provider), and then set the parameters generated by the IdP into &lt;code&gt;.env&lt;/code&gt; file. You can use this CloudFront Extension CDK solution to complete the deployment. After practicing, it should be completed within 20 minutes.&lt;/p&gt;

&lt;p&gt;This article is organized in order for future education and training material, and is divided into three parts:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;At the beginning, we will introduce use cases, architecture, OAuth 2.0 protocol flow, and Grant Type: Authorization Code process&lt;/li&gt;
&lt;li&gt;Then select and configure a IdP you like (this part is expected to be expanded and updated in the future)&lt;/li&gt;
&lt;li&gt;Finally, "CloudFront Extension OAuth2 Getting Started" takes everyone to actually operate this CDK&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  1. Use Case
&lt;/h2&gt;

&lt;p&gt;In recent years, the use of &lt;a href="https://jamstack.org/generators/" rel="noopener noreferrer"&gt;static site generators&lt;/a&gt; has gradually become a mainstream tool for setting up blogs or document sites. The generated static files, in addition to putting &lt;a href="https://pages.github.com/" rel="noopener noreferrer"&gt;GitHub Pages&lt;/a&gt;, another good place is &lt;a href="https://aws.amazon.com/tw/s3/" rel="noopener noreferrer"&gt;Amazon S3&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Putting &lt;a href="https://aws.amazon.com/tw/cloudfront/" rel="noopener noreferrer"&gt;Amazon CloudFront&lt;/a&gt; as a CDN in front of Amazon S3 is also a common choice.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb0i2u8ny2k1yu9d9dmi8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb0i2u8ny2k1yu9d9dmi8.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In some usage scenarios, users are expected to log in before they can view the content of the website or document. In this case, you can request &lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/lambda-edge.html" rel="noopener noreferrer"&gt;CloudFront Lambda@Edge&lt;/a&gt; to help us execute a Lambda program, log in and OAuth 2.0 authorization process with the IdP (Identity Provider) specified by ourselves.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F432kwf8gtuo5khukdv5o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F432kwf8gtuo5khukdv5o.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this case, we will use "Viewer request", one of the four trigger points of CloudFront Lambda@Edge to trigger the execution of the Lambda program we specify to communicate with the IdP. If the OAuth2.0 Authorization Code is successfully authorized, the user will be allowed to watch the origin - the content of website or document.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1891apbrijbp3mikaygv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1891apbrijbp3mikaygv.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then look at two demo videos (corresponding to different IdPs, but both use standard OAuth 2.0 and OpenID) to quickly understand the use case that this article wants to implement:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The following figure uses Auth0 (IdP) + OAuth2 Authentication (CloudFront Extension) implemented in this article&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.ernestchiang.com%2Fimg%2F2021%2F2021-04-13-implementing-cloudfront-lambda-at-edge-oauth2%2FCloudfront-extension-OAuth2-demo-medium.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.ernestchiang.com%2Fimg%2F2021%2F2021-04-13-implementing-cloudfront-lambda-at-edge-oauth2%2FCloudfront-extension-OAuth2-demo-medium.gif" alt="demo1 video"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;(This GIF has too many frames, please kindly visit Ernest's origin post: &lt;a href="https://www.ernestchiang.com/en/posts/2021/2021-04-13-implementing-cloudfront-lambda-at-edge-oauth2/" rel="noopener noreferrer"&gt;https://www.ernestchiang.com/en/posts/2021/2021-04-13-implementing-cloudfront-lambda-at-edge-oauth2/&lt;/a&gt; )&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The following figure uses self-built KeyCloak (IdP) + OAuth2 Authentication (CloudFront Extension) implemented in this article

&lt;ul&gt;
&lt;li&gt;Also use CDK to quickly deploy KeyCloak&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.ernestchiang.com%2Fimg%2F2021%2F2021-04-13-implementing-cloudfront-lambda-at-edge-oauth2%2FCloudFront-plus-Oauth2-KeyCloak-demo.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.ernestchiang.com%2Fimg%2F2021%2F2021-04-13-implementing-cloudfront-lambda-at-edge-oauth2%2FCloudFront-plus-Oauth2-KeyCloak-demo.gif" alt="demo2 video"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;(This GIF has too many frames, please kindly visit Ernest's origin post: &lt;a href="https://www.ernestchiang.com/en/posts/2021/2021-04-13-implementing-cloudfront-lambda-at-edge-oauth2/" rel="noopener noreferrer"&gt;https://www.ernestchiang.com/en/posts/2021/2021-04-13-implementing-cloudfront-lambda-at-edge-oauth2/&lt;/a&gt; )&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Amazon CloudFront Extensions
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://awslabs.github.io/aws-cloudfront-extensions/" rel="noopener noreferrer"&gt;Amazon CloudFront Extensions&lt;/a&gt; is a combination of using Lambda@Edge to extend CloudFront to implement various rich features. Originally implemented using AWS CloudFormation, but this time Pahud invited us to use the AWS CDK method to implement it.&lt;/p&gt;

&lt;p&gt;The git repo we implemented this time is placed in Pahud's home: &lt;a href="https://github.com/pahud/cdk-cloudfront-plus" rel="noopener noreferrer"&gt;https://github.com/pahud/cdk-cloudfront-plus&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The name of the extension I implemented this time is "&lt;a href="https://github.com/pahud/cdk-cloudfront-plus/tree/main/src/demo/cf-authentication-by-oauth2" rel="noopener noreferrer"&gt;OAuth2 Authentication&lt;/a&gt;", project number "SO8131", directory name "cf-authentication-by-oauth2".&lt;/p&gt;

&lt;p&gt;The goal of implementation is to create a universal package (Lambda@Edge), which can be set to correspond to various parameters provided by IdP (Identity Provider) by setting environment variables, such as client id, client secret, callback URL, etc. And hope to reduce package dependencies and use TypeScript throughout.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. OAuth 2.0 Grant Type: Authorization Code
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://tools.ietf.org/html/rfc6749" rel="noopener noreferrer"&gt;RFC6749&lt;/a&gt; defines The OAuth 2.0 Authorization Framework, &lt;a href="https://en.wikipedia.org/wiki/OpenID" rel="noopener noreferrer"&gt;OpenID&lt;/a&gt; implemented OAuth 2.0 and integrated account information. Simply understand that OAuth 2.0 is a theory, and OpenID is one of the implementation methods based on this theory.&lt;/p&gt;

&lt;p&gt;OAuth 2.0 defines four roles, six steps, Three round trips. Refer to the following Protocol Flow:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9n23y6wt5y0feyq49oax.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9n23y6wt5y0feyq49oax.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Client: Authorization Request --&amp;gt; Resource Owner: Authorization Grant&lt;/li&gt;
&lt;li&gt;Client: Authorization Grant --&amp;gt; Authorization Server: Access Token&lt;/li&gt;
&lt;li&gt;Client: Access Token --&amp;gt; Resource Server: Protected Resource&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Quick summary: three simple steps: first take a code --&amp;gt; take the code for a (access) token --&amp;gt; take the token for resources.&lt;/p&gt;




&lt;p&gt;OAuth 2.0 defines four Authorization Grant Types:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Authorization Code&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Authorization Code&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Authorization Code with PKCE&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Implicit&lt;/li&gt;

&lt;li&gt;Resource Owner Password Credentials&lt;/li&gt;

&lt;li&gt;Client Credentials&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Quick summary: The context in this article is suitable for &lt;strong&gt;Authorization Code&lt;/strong&gt;.&lt;/p&gt;




&lt;p&gt;After establishing the process structure and narrowing down the scope of using the Authorization Code, then set up the IdP you choose, create a client in the IdP environment, and obtain various environmental variables of the IdP and the client.&lt;/p&gt;

&lt;p&gt;In the process, &lt;del&gt;we will encounter various IdP hidden magic logic, oh no, I mean&lt;/del&gt; IdP, in order to strengthen the verification process, there will be different details that need to be paid attention to. E.g&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The Auth0 document does not mention but the authorize parameter combination must be &lt;code&gt;response_type=code&lt;/code&gt; with &lt;code&gt;scope=openid&lt;/code&gt; to get the JWT token. (&lt;a href="https://community.auth0.com/t/oauth-token-not-returning-id-token/8303" rel="noopener noreferrer"&gt;reference source&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;KeyCloak stipulates which URL the Client comes from at the beginning, and the subsequent specified &lt;code&gt;redirect_uri&lt;/code&gt; must be exactly the same URL before releasing, otherwise KeyCloak will keep spraying &lt;code&gt;400 Bad Request&lt;/code&gt; with a mysterious and unknown error log: &lt;code&gt;[0m[33m11:57:34,772 WARN [org.keycloak.events] (default task-97) type=CODE_TO_TOKEN_ERROR, realmId=RealmDemoCDK, clientId=demo-cloudfront-plus, userId=2ae58a4c-9b3e-4f0e-b58d-b9462e73105a, ipAddress=10.0.9.157, error=invalid_code, grant_type=authorization_code, code_id=fbb08df8-1af1-4960-a9ac-ab80e0b3d377, client_auth_method=client-secret&lt;/code&gt;. (&lt;a href="https://stackoverflow.com/questions/45860313/keycloak-code-to-token-error-after-user-is-authenticated" rel="noopener noreferrer"&gt;reference source&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Please &lt;a href="https://www.ernestchiang.com/en/posts/2021/2021-04-13-implementing-cloudfront-lambda-at-edge-oauth2/#3-oauth-20-grant-type-authorization-code" rel="noopener noreferrer"&gt;visit my blog&lt;/a&gt; to continue the section #4 ~ #7...&lt;/p&gt;

</description>
      <category>cdk</category>
      <category>cloudfront</category>
      <category>authorization</category>
      <category>lambda</category>
    </item>
  </channel>
</rss>
