{"id":1068,"date":"2021-09-13T16:37:32","date_gmt":"2021-09-13T20:37:32","guid":{"rendered":"https:\/\/heisbudi.com\/?p=1068"},"modified":"2021-09-14T13:06:36","modified_gmt":"2021-09-14T17:06:36","slug":"stitching-up-together-secure-firebase-authentication-on-google-app-engine-using-custom-domain","status":"publish","type":"post","link":"https:\/\/heisbudi.com\/?p=1068","title":{"rendered":"Stitching up Together Secure Firebase Authentication on Google App Engine Using Custom Domain"},"content":{"rendered":"\n<h2>What This Post is<\/h2>\n\n\n\n<p>This post will show you how to <em><strong>correctly<\/strong><\/em> and securely (using SSL) set up your web app hosted on Google App Engine (written in Python) using Firebase Authentication and a custom domain (as opposed to project-id.firebaseapp.com). Correctly is highlighted because I spent days trying to set this up with no luck. Several errors message I was getting was:<\/p>\n\n\n\n<ul><li>This browser is not supported or 3rd party cookies and data may be disabled (on Chrome)<\/li><\/ul>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"642\" height=\"132\" src=\"https:\/\/heisbudi.com\/wp-content\/uploads\/2021\/08\/Screen-Shot-2021-08-30-at-2.03.41-PM.png\" alt=\"3rd Party Cookie Warning on Chrome \" class=\"wp-image-1069\" srcset=\"https:\/\/heisbudi.com\/wp-content\/uploads\/2021\/08\/Screen-Shot-2021-08-30-at-2.03.41-PM.png 642w, https:\/\/heisbudi.com\/wp-content\/uploads\/2021\/08\/Screen-Shot-2021-08-30-at-2.03.41-PM-300x62.png 300w\" sizes=\"(max-width: 642px) 100vw, 642px\" \/><figcaption>3rd Party Cookie Warning on Chrome<\/figcaption><\/figure>\n\n\n\n<ul><li>Invalid SSL. I have a valid SSL setup for my domain, but when users are trying to login, they are getting an invalid SSL saying that my domain&#8217;s certificate is not issued by firebaseapp.com. Basically the URL on the browser is your custom domain (e.g. example.com), but the authentication is happening against firebaseapp.com. Hence the warning.<\/li><\/ul>\n\n\n\n<figure class=\"wp-block-image size-large is-resized is-style-default\"><img loading=\"lazy\" src=\"https:\/\/heisbudi.com\/wp-content\/uploads\/2021\/08\/Screen-Shot-2021-08-30-at-3.04.52-PM-1024x776.png\" alt=\"Invalid SSL warning when logging in\" class=\"wp-image-1070\" width=\"512\" height=\"388\" srcset=\"https:\/\/heisbudi.com\/wp-content\/uploads\/2021\/08\/Screen-Shot-2021-08-30-at-3.04.52-PM-1024x776.png 1024w, https:\/\/heisbudi.com\/wp-content\/uploads\/2021\/08\/Screen-Shot-2021-08-30-at-3.04.52-PM-300x227.png 300w, https:\/\/heisbudi.com\/wp-content\/uploads\/2021\/08\/Screen-Shot-2021-08-30-at-3.04.52-PM-768x582.png 768w, https:\/\/heisbudi.com\/wp-content\/uploads\/2021\/08\/Screen-Shot-2021-08-30-at-3.04.52-PM.png 1264w\" sizes=\"(max-width: 512px) 100vw, 512px\" \/><figcaption>Invalid SSL Error when Logging in<\/figcaption><\/figure>\n\n\n\n<ul><li>Authorization and Redirect error<\/li><\/ul>\n\n\n\n<figure class=\"wp-block-image size-large is-resized is-style-default\"><img loading=\"lazy\" src=\"https:\/\/heisbudi.com\/wp-content\/uploads\/2021\/08\/Screen-Shot-2021-08-30-at-3.12.59-PM-1-704x1024.png\" alt=\"Authorization and Redirect Error\" class=\"wp-image-1072\" width=\"352\" height=\"512\" srcset=\"https:\/\/heisbudi.com\/wp-content\/uploads\/2021\/08\/Screen-Shot-2021-08-30-at-3.12.59-PM-1-704x1024.png 704w, https:\/\/heisbudi.com\/wp-content\/uploads\/2021\/08\/Screen-Shot-2021-08-30-at-3.12.59-PM-1-206x300.png 206w, https:\/\/heisbudi.com\/wp-content\/uploads\/2021\/08\/Screen-Shot-2021-08-30-at-3.12.59-PM-1-768x1117.png 768w, https:\/\/heisbudi.com\/wp-content\/uploads\/2021\/08\/Screen-Shot-2021-08-30-at-3.12.59-PM-1.png 784w\" sizes=\"(max-width: 352px) 100vw, 352px\" \/><figcaption>Authorization and Redirect Error<\/figcaption><\/figure>\n\n\n\n<h2>What This Post is NOT<\/h2>\n\n\n\n<p>This post is NOT a tutorial on how setup each environment separately. This post assume you have the following setup successfully, but you are experiencing one (or more) error mentioned above. <\/p>\n\n\n\n<ul><li><a rel=\"noreferrer noopener\" href=\"https:\/\/firebase.google.com\/docs\/auth\/web\/start\" target=\"_blank\">Firebase authentication<\/a><\/li><li>Your own domain (e.g. example.com)<\/li><li>Access to add your own <a rel=\"noreferrer noopener\" href=\"https:\/\/support.google.com\/domains\/answer\/3290350?authuser=2&amp;hl=en\" target=\"_blank\">resource records<\/a> (e.g. CNAME, AAAA, MX, etc) from your domain  provider<\/li><li><a rel=\"noreferrer noopener\" href=\"https:\/\/cloud.google.com\/appengine\/docs\/standard\/python3\/mapping-custom-domains\" target=\"_blank\">Custom domain<\/a> for your web app on Google AppEngine (e.g. https:\/\/example.com as opposed to https:\/\/project-id.ue.r.appspot.com\/) <\/li><li><a rel=\"noreferrer noopener\" href=\"https:\/\/cloud.google.com\/appengine\/docs\/standard\/python3\/securing-custom-domains-with-ssl\" target=\"_blank\">SSL<\/a> either using Google Managed SSL, purchased separately, or issued by <a href=\"https:\/\/letsencrypt.org\/getting-started\/\">Let&#8217;s Encrypt<\/a>, an open-source Certificate Authority. <\/li><\/ul>\n\n\n\n<p>Each corresponding link above will guide you to setup each environment.<\/p>\n\n\n\n<h2>Tips for Faster Debugging<\/h2>\n\n\n\n<p>The setup shown on this post requires readers to add domain <a rel=\"noreferrer noopener\" href=\"https:\/\/support.google.com\/domains\/answer\/3290350?authuser=2&amp;hl=en\" target=\"_blank\">resource records<\/a> (e.g. CNAME, AAAA, MX, etc) from a domain provider. Although a DNS record eventually propagate to other DNS providers, this process usually takes time (<a rel=\"noreferrer noopener\" href=\"https:\/\/constellix.com\/news\/what-is-dns-propagation#:~:text=DNS%20Propagation%20Time&amp;text=There's%20no%20concrete%20answer%20for,values%20of%20your%20DNS%20records.\" target=\"_blank\">up to 72 hours<\/a>). For debugging purpose, it&#8217;s a good idea to change the DNS server on the computer you are using to debug to the DNS server provided by your domain provider. This way you don&#8217;t need to wait too long.<\/p>\n\n\n\n<h2>Wiring Everything up<\/h2>\n\n\n\n<ol><li>Setup Custom Domain on App Engine<br>Follow the <a rel=\"noreferrer noopener\" href=\"https:\/\/cloud.google.com\/appengine\/docs\/standard\/python3\/mapping-custom-domains\" data-type=\"URL\" data-id=\"https:\/\/cloud.google.com\/appengine\/docs\/standard\/python3\/mapping-custom-domains\" target=\"_blank\">instruction<\/a> listed on Google&#8217;s documentation on how to accomplish this. You can also setup www subdomain (e.g. www.example.com and example.com will lead to the same landing page) if you choose to do so. <br><\/li><li>Create Domain Resource Records<br>At the end of the Step 1 above, Google will prompt you to add domain resource records. If you purchase your domain from Google Domain, you can follow the instruction <a href=\"https:\/\/support.google.com\/domains\/answer\/3290350?hl=en#zippy=%2Cadd-a-resource-record\">here<\/a>. If you purchase your domain somewhere else, consult with your domain&#8217;s registrar on how to add resource records for the domain you purchase. Example of domain resource records that needs to be added are as follow<br><div class=\"wp-block-image is-style-default\"><figure class=\"aligncenter size-large is-resized\"><img loading=\"lazy\" width=\"435\" height=\"479\" src=\"https:\/\/heisbudi.com\/wp-content\/uploads\/2021\/08\/Screen-Shot-2021-08-31-at-12.18.51-PM.png\" alt=\"Domain Resource Records Example\" class=\"wp-image-1074\" srcset=\"https:\/\/heisbudi.com\/wp-content\/uploads\/2021\/08\/Screen-Shot-2021-08-31-at-12.18.51-PM.png 580w, https:\/\/heisbudi.com\/wp-content\/uploads\/2021\/08\/Screen-Shot-2021-08-31-at-12.18.51-PM-273x300.png 273w\" sizes=\"(max-width: 435px) 100vw, 435px\" \/><figcaption><\/figcaption><\/figure><\/div><\/li><li>Create a Custom Domain using Firebase Hosting<br>This is the crucial part I was missing. When this step wasn&#8217;t done or or done incorrectly, it causes clients&#8217; browser to think that Firebase authentication is not coming from your custom domain, which results in 3rd party cookie warning shown above. <br><br>From the Firebase web <a rel=\"noreferrer noopener\" href=\"https:\/\/console.firebase.google.com\/project\/_\/hosting\/main?hl=NO\" target=\"_blank\">console<\/a>, go to the hosting section, and add a custom domain. You might need to click through all the tutorial steps, but you don&#8217;t have to actually do the setup process laid out in the tutorial. <br> <figure class=\"wp-block-image size-large is-style-default\"><img loading=\"lazy\" width=\"1024\" height=\"558\" src=\"https:\/\/heisbudi.com\/wp-content\/uploads\/2021\/09\/del-1-1024x558.png\" alt=\"Adding a Custom Domain to Firebase Hosting\" class=\"wp-image-1082\" srcset=\"https:\/\/heisbudi.com\/wp-content\/uploads\/2021\/09\/del-1-1024x558.png 1024w, https:\/\/heisbudi.com\/wp-content\/uploads\/2021\/09\/del-1-300x163.png 300w, https:\/\/heisbudi.com\/wp-content\/uploads\/2021\/09\/del-1-768x418.png 768w, https:\/\/heisbudi.com\/wp-content\/uploads\/2021\/09\/del-1.png 1179w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><figcaption>Adding a Custom Domain to Firebase Hosting<\/figcaption><\/figure><br>Do <em>NOT<\/em> use your second level domain (e.g. example.com). Instead, use a subdomain so that the clients&#8217; browsers see a single domain for the redirect login. For example, use <em>signin.example.com<\/em> when adding a custom domain to be hosted by Firebase in this step. This way the browser will see one domain both when a user lands on the main page (e.g. example.com), and will again see the same domain (i.e. signin.example.com) when they are prompted to login.  Without this setup, when users visit a landing page (e.g. example.com) and attempt a login, the login will be redirected to firebaseapp.com and cookies will also be set by firebaseapp.com.<br><br>Once this step is done, you will be prompted to add an A record in your domain. Go ahead and do so. It might take some time for the domain to propagate through. Once the setup is done, the custom domain will look like the following, indicating that the custom domain is connected. Make sure to wait until the status is changed to &#8220;Connected&#8221; before proceeding to Step 4..<br><figure class=\"wp-block-image size-large is-style-default\"><img loading=\"lazy\" width=\"1024\" height=\"516\" src=\"https:\/\/heisbudi.com\/wp-content\/uploads\/2021\/09\/Screen-Shot-2021-09-10-at-3.11.30-PM-1-1024x516.png\" alt=\"Connected Custom Domain\" class=\"wp-image-1084\" srcset=\"https:\/\/heisbudi.com\/wp-content\/uploads\/2021\/09\/Screen-Shot-2021-09-10-at-3.11.30-PM-1-1024x516.png 1024w, https:\/\/heisbudi.com\/wp-content\/uploads\/2021\/09\/Screen-Shot-2021-09-10-at-3.11.30-PM-1-300x151.png 300w, https:\/\/heisbudi.com\/wp-content\/uploads\/2021\/09\/Screen-Shot-2021-09-10-at-3.11.30-PM-1-768x387.png 768w, https:\/\/heisbudi.com\/wp-content\/uploads\/2021\/09\/Screen-Shot-2021-09-10-at-3.11.30-PM-1.png 1226w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><figcaption>Connected Custom Domain<\/figcaption><\/figure><\/li><li>Add an Authorized redirect URIs on Google API Console<br>When this step isn&#8217;t done (properly), Authorization and Redirect error pictured above will appear when users attempt to sign-in.  Go to <a rel=\"noreferrer noopener\" href=\"https:\/\/console.cloud.google.com\/apis\" target=\"_blank\">Google API Console<\/a> for your project, go to Credentials section and edit the OAuth 2.0 Client IDs as pictured below. <br><br><figure class=\"wp-block-image size-large is-style-default\"><img loading=\"lazy\" width=\"1024\" height=\"641\" src=\"https:\/\/heisbudi.com\/wp-content\/uploads\/2021\/09\/Screen-Shot-2021-09-13-at-10.35.26-AM-1024x641.png\" alt=\"Editing OAuth 2.0 Client IDs\" class=\"wp-image-1086\" srcset=\"https:\/\/heisbudi.com\/wp-content\/uploads\/2021\/09\/Screen-Shot-2021-09-13-at-10.35.26-AM-1024x641.png 1024w, https:\/\/heisbudi.com\/wp-content\/uploads\/2021\/09\/Screen-Shot-2021-09-13-at-10.35.26-AM-300x188.png 300w, https:\/\/heisbudi.com\/wp-content\/uploads\/2021\/09\/Screen-Shot-2021-09-13-at-10.35.26-AM-768x481.png 768w, https:\/\/heisbudi.com\/wp-content\/uploads\/2021\/09\/Screen-Shot-2021-09-13-at-10.35.26-AM-1536x961.png 1536w, https:\/\/heisbudi.com\/wp-content\/uploads\/2021\/09\/Screen-Shot-2021-09-13-at-10.35.26-AM.png 1946w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><figcaption>Editing OAuth 2.0 Client IDs<\/figcaption><\/figure><br><br>Go to the Authorized URIs Redirect session, add the custom sub-domain created in Step 3. above and suffix it with <strong>\/__\/auth\/handler<\/strong>. For example, if your domain is <em>example.com<\/em>, in Step 3. above you would create a sub-domain called <em>signin.example.com<\/em> and in this step, the URI you would add is <em>https:\/\/signin.example.com\/__\/auth\/handler<\/em>. <br><br><figure class=\"wp-block-image size-large is-style-default\"><img loading=\"lazy\" width=\"1012\" height=\"650\" src=\"https:\/\/heisbudi.com\/wp-content\/uploads\/2021\/09\/Screen-Shot-2021-09-13-at-10.54.33-AM.png\" alt=\"Authorized Redirect URI with Custom Domain\" class=\"wp-image-1088\" srcset=\"https:\/\/heisbudi.com\/wp-content\/uploads\/2021\/09\/Screen-Shot-2021-09-13-at-10.54.33-AM.png 1012w, https:\/\/heisbudi.com\/wp-content\/uploads\/2021\/09\/Screen-Shot-2021-09-13-at-10.54.33-AM-300x193.png 300w, https:\/\/heisbudi.com\/wp-content\/uploads\/2021\/09\/Screen-Shot-2021-09-13-at-10.54.33-AM-768x493.png 768w\" sizes=\"(max-width: 1012px) 100vw, 1012px\" \/><figcaption>Authorized Redirect URI with Custom Domain<\/figcaption><\/figure><\/li><li>Firebase Configuration on HTML page(s)<br>Now that everything is setup on the backend, we&#8217;ll need to change the Firebase configuration on HTML page(s) that uses Firebase to reflect the changes above. By default the domain use for authorization in Firebase is: <br><strong>authDomain: &#8220;&lt;project-id&gt;.firebaseapp.com&#8221;<\/strong><br>Change the default value with the custom subdomain value specified in Step 3. above. An example is shown below. <br><br><figure class=\"wp-block-image size-large is-style-default\"><img loading=\"lazy\" width=\"1024\" height=\"541\" src=\"https:\/\/heisbudi.com\/wp-content\/uploads\/2021\/09\/Screen-Shot-2021-09-13-at-1.48.24-PM-1024x541.png\" alt=\"Firebase Custom Domain Configuration\" class=\"wp-image-1089\" srcset=\"https:\/\/heisbudi.com\/wp-content\/uploads\/2021\/09\/Screen-Shot-2021-09-13-at-1.48.24-PM-1024x541.png 1024w, https:\/\/heisbudi.com\/wp-content\/uploads\/2021\/09\/Screen-Shot-2021-09-13-at-1.48.24-PM-300x158.png 300w, https:\/\/heisbudi.com\/wp-content\/uploads\/2021\/09\/Screen-Shot-2021-09-13-at-1.48.24-PM-768x406.png 768w, https:\/\/heisbudi.com\/wp-content\/uploads\/2021\/09\/Screen-Shot-2021-09-13-at-1.48.24-PM-1536x811.png 1536w, https:\/\/heisbudi.com\/wp-content\/uploads\/2021\/09\/Screen-Shot-2021-09-13-at-1.48.24-PM.png 1750w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><figcaption>Firebase Custom Domain Configuration<\/figcaption><\/figure><\/li><\/ol>\n\n\n\n<p>At this point everything should work properly<\/p>\n\n\n\n<p><\/p>\n<div data-counters='1' data-style='square' data-size='regular' data-url='https:\/\/heisbudi.com\/?p=1068' data-title='Stitching up Together Secure Firebase Authentication on Google App Engine Using Custom Domain' class='linksalpha_container linksalpha_app_3'><a href='\/\/www.linksalpha.com\/share?network='facebook' class='linksalpha_icon_facebook'><\/a><a href='\/\/www.linksalpha.com\/share?network='twitter' class='linksalpha_icon_twitter'><\/a><a href='\/\/www.linksalpha.com\/share?network='googleplus' class='linksalpha_icon_googleplus'><\/a><a href='\/\/www.linksalpha.com\/share?network='mail' class='linksalpha_icon_mail'><\/a><\/div><div data-position='' data-url='https:\/\/heisbudi.com\/?p=1068' data-title='Stitching up Together Secure Firebase Authentication on Google App Engine Using Custom Domain' class='linksalpha_container linksalpha_app_7'><a href='\/\/www.linksalpha.com\/share?network='facebook' class='linksalpha_icon_facebook'><\/a><a href='\/\/www.linksalpha.com\/share?network='twitter' class='linksalpha_icon_twitter'><\/a><a href='\/\/www.linksalpha.com\/share?network='googleplus' class='linksalpha_icon_googleplus'><\/a><a href='\/\/www.linksalpha.com\/share?network='mail' class='linksalpha_icon_mail'><\/a><\/div>","protected":false},"excerpt":{"rendered":"<p>What This Post is This post will show you how to correctly and securely (using SSL) set up your web app hosted on Google App Engine (written in Python) using Firebase Authentication and a custom domain (as opposed to project-id.firebaseapp.com). Correctly is highlighted because I spent days trying to set this up with no luck. <a class=\"read-more\" href=\"https:\/\/heisbudi.com\/?p=1068\">[&hellip;]<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[1],"tags":[47,48,44,45,46],"_links":{"self":[{"href":"https:\/\/heisbudi.com\/index.php?rest_route=\/wp\/v2\/posts\/1068"}],"collection":[{"href":"https:\/\/heisbudi.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/heisbudi.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/heisbudi.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/heisbudi.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1068"}],"version-history":[{"count":14,"href":"https:\/\/heisbudi.com\/index.php?rest_route=\/wp\/v2\/posts\/1068\/revisions"}],"predecessor-version":[{"id":1102,"href":"https:\/\/heisbudi.com\/index.php?rest_route=\/wp\/v2\/posts\/1068\/revisions\/1102"}],"wp:attachment":[{"href":"https:\/\/heisbudi.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1068"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/heisbudi.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1068"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/heisbudi.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1068"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}