<?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: OdedBD</title>
    <description>The latest articles on DEV Community by OdedBD (@bdoded).</description>
    <link>https://dev.to/bdoded</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%2F25015%2F058acdb5-feae-4e58-9545-4ba674d37d38.jpeg</url>
      <title>DEV Community: OdedBD</title>
      <link>https://dev.to/bdoded</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/bdoded"/>
    <language>en</language>
    <item>
      <title>Load external data into OPA: The Good, The Bad, and The Ugly</title>
      <dc:creator>OdedBD</dc:creator>
      <pubDate>Mon, 04 Apr 2022 14:48:28 +0000</pubDate>
      <link>https://dev.to/permit_io/load-external-data-into-opa-the-good-the-bad-and-the-ugly-26lc</link>
      <guid>https://dev.to/permit_io/load-external-data-into-opa-the-good-the-bad-and-the-ugly-26lc</guid>
      <description>&lt;p&gt;There are several ways to create a data fetching mechanism for OPA - each of them has its pros and cons. To make sense of these different methods, I've decided to create this guide that will help you figure out which data fetching method would be best for you, with full knowledge of each method’s ‘good, bad, and ugly’ aspects.&lt;br&gt;
 &lt;/p&gt;
&lt;h1&gt;
  
  
  TL;DR - 
&lt;/h1&gt;

&lt;p&gt;The methods that we are going to review are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Including data in JWT tokens&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Overload input for OPA within the query&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Polling for data using Bundles&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Pushing data into OPA using the API&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Pulling data using OPA during Policy Evaluation&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;OPAL (Open Policy Administration Layer)&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Before we dive into details, let’s first cover some basics - &lt;/p&gt;
&lt;h2&gt;
  
  
  What is OPA
&lt;/h2&gt;

&lt;p&gt;Authorization is becoming increasingly complicated - applications are getting bigger and require handling more users than ever before, policies are becoming more complex and dependent on multiple factors (Like a client’s location, time of the action, user roles, and relations to resources).&lt;br&gt;
This is where OPA (Open Policy Agent) comes in - OPA is a great open-source tool that allows us to evaluate complicated policies. It’s fast, part of the CNCF (Which means it adheres to CNCF’s guidelines and standards), and is used for handling permissions in some of the largest companies in the world (e.g. Netflix, Pinterest, and others). You can check out an introduction to OPA &lt;a href="https://www.permit.io/blog/introduction-to-opa" rel="noopener noreferrer"&gt;here&lt;/a&gt;. &lt;br&gt;
⁠&lt;/p&gt;
&lt;h2&gt;
  
  
  How OPA Works with Data
&lt;/h2&gt;

&lt;p&gt;Managing policies with OPA often requires relevant contextual data - Information about the user, the resource they are trying to access, etc. Without this information, OPA will not be able to make the right decisions when it comes to deciding on policies. &lt;br&gt;
For example - a policy that states “Only paying users can access this feature” requires OPA to have information on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Who my users are&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Which one of them is a paying user, and which isn’t&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A policy that states “Users in the application can only access their own photos, or those of their children” requires OPA to know:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Who are the application’s users&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Which user is a parent, which user is a child, and which user relates to who&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Which photo belongs to each user&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Having access to this contextual data is thus critical for OPA to be able to make its decisions. &lt;/p&gt;

&lt;p&gt;The bottom-line question is - how can we bring this data into OPA, and which way is the most effective to do so? &lt;/p&gt;
&lt;h2&gt;
  
  
  The data fetching mechanism: Basic requirements
&lt;/h2&gt;

&lt;p&gt; &lt;br&gt;
Before we dive into the different methods of fetching data for OPA, let’s agree on a couple of basic guidelines for how this data fetching mechanism should work:&lt;br&gt;
It's necessary to be able to handle data about policies on a large scale&lt;/p&gt;

&lt;p&gt;Because data can come from many sources, thus getting very complex very quickly, we want this mechanism to be as easily manageable as possible.&lt;/p&gt;

&lt;p&gt;The data fetching mechanism needs to be operational in real-time (This is a crucial component that will allow us to avoid a &lt;a href="https://storage.googleapis.com/pub-tools-public-publication-data/pdf/41f08f03da59f5518802898f68730e247e23c331.pdf" rel="noopener noreferrer"&gt;“New enemy attack”&lt;/a&gt; - a situation where a user with revoked permission can still access sensitive data because the permissions have not been updated in time between the different parts of the system).&lt;/p&gt;

&lt;p&gt;It should be easy to maintain because the need for access control is here to stay and is likely to evolve in the future.&lt;/p&gt;

&lt;p&gt;Now that we've established some basic requirements, let’s dive into the various data fetching mechanisms we can utilize to solve our issue in the most efficient way.&lt;/p&gt;

&lt;p&gt;Let’s dive in!&lt;/p&gt;

&lt;p&gt;&lt;br&gt;
&lt;a&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;
  
  
  1. Including data in JWT tokens:
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Far131kmbns6u3bk7o5pc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Far131kmbns6u3bk7o5pc.png" alt="Including data in JWT tokens" width="654" height="630"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://tools.ietf.org/html/rfc7519" rel="noopener noreferrer"&gt;JSON Web Tokens (JWT)&lt;/a&gt; allow you to securely transmit signed JSON data between software systems and are usually produced during the authentication process. JWTs can be sent to OPA as inputs thus enabling OPA to make decisions about a Policy query.&lt;/p&gt;

&lt;p&gt;For example, this is what a &lt;a href="https://jwt.io/#debugger-io?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwicm9sZXMiOlsiYWRtaW4iXSwicmVsYXRlZF9pbWFnZXMiOlsiaW1hZ2UxLnBuZyIsImltYWdlMi5wbmciXSwiaWF0IjoxNTE2MjM5MDIyfQ.Qkur5-lKPBMhZLqgl-BjkZzyjiHVSoq1p1C36vUiuQU" rel="noopener noreferrer"&gt;JWT with authorization data looks like&lt;/a&gt;:&lt;/p&gt;

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

&lt;p&gt;The first part is the algorithm for the secure signing, and in the middle, we can see the roles and related images for our authorization.&lt;/p&gt;

&lt;p&gt;The good:&lt;br&gt;
JWTs are an easy-to-use well-known technology that you probably already utilize in your system (as part of the authentication layer).&lt;/p&gt;

&lt;p&gt;The bad:&lt;br&gt;
JWTs have a size limit - not everything can be decoded into a JWT, while it looks OK in the example presented above, if a user &lt;a href="https://jwt.io/#debugger-io?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwicm9sZXMiOlsiYWRtaW4iXSwicmVsYXRlZF9pbWFnZXMiOlsiaW1hZ2UwLnBuZyIsImltYWdlMS5wbmciLCJpbWFnZTIucG5nIiwiaW1hZ2UzLnBuZyIsImltYWdlNC5wbmciLCJpbWFnZTUucG5nIiwiaW1hZ2U2LnBuZyIsImltYWdlNy5wbmciLCJpbWFnZTgucG5nIiwiaW1hZ2U5LnBuZyIsImltYWdlMTAucG5nIiwiaW1hZ2UxMS5wbmciLCJpbWFnZTEyLnBuZyIsImltYWdlMTMucG5nIiwiaW1hZ2UxNC5wbmciLCJpbWFnZTE1LnBuZyIsImltYWdlMTYucG5nIiwiaW1hZ2UxNy5wbmciLCJpbWFnZTE4LnBuZyIsImltYWdlMTkucG5nIiwiaW1hZ2UyMC5wbmciLCJpbWFnZTIxLnBuZyIsImltYWdlMjIucG5nIiwiaW1hZ2UyMy5wbmciLCJpbWFnZTI0LnBuZyIsImltYWdlMjUucG5nIiwiaW1hZ2UyNi5wbmciLCJpbWFnZTI3LnBuZyIsImltYWdlMjgucG5nIiwiaW1hZ2UyOS5wbmciLCJpbWFnZTMwLnBuZyIsImltYWdlMzEucG5nIiwiaW1hZ2UzMi5wbmciLCJpbWFnZTMzLnBuZyIsImltYWdlMzQucG5nIiwiaW1hZ2UzNS5wbmciLCJpbWFnZTM2LnBuZyIsImltYWdlMzcucG5nIiwiaW1hZ2UzOC5wbmciLCJpbWFnZTM5LnBuZyIsImltYWdlNDAucG5nIiwiaW1hZ2U0MS5wbmciLCJpbWFnZTQyLnBuZyIsImltYWdlNDMucG5nIiwiaW1hZ2U0NC5wbmciLCJpbWFnZTQ1LnBuZyIsImltYWdlNDYucG5nIiwiaW1hZ2U0Ny5wbmciLCJpbWFnZTQ4LnBuZyIsImltYWdlNDkucG5nIiwiaW1hZ2U1MC5wbmciLCJpbWFnZTUxLnBuZyIsImltYWdlNTIucG5nIiwiaW1hZ2U1My5wbmciLCJpbWFnZTU0LnBuZyIsImltYWdlNTUucG5nIiwiaW1hZ2U1Ni5wbmciLCJpbWFnZTU3LnBuZyIsImltYWdlNTgucG5nIiwiaW1hZ2U1OS5wbmciLCJpbWFnZTYwLnBuZyIsImltYWdlNjEucG5nIiwiaW1hZ2U2Mi5wbmciLCJpbWFnZTYzLnBuZyIsImltYWdlNjQucG5nIiwiaW1hZ2U2NS5wbmciLCJpbWFnZTY2LnBuZyIsImltYWdlNjcucG5nIiwiaW1hZ2U2OC5wbmciLCJpbWFnZTY5LnBuZyIsImltYWdlNzAucG5nIiwiaW1hZ2U3MS5wbmciLCJpbWFnZTcyLnBuZyIsImltYWdlNzMucG5nIiwiaW1hZ2U3NC5wbmciLCJpbWFnZTc1LnBuZyIsImltYWdlNzYucG5nIiwiaW1hZ2U3Ny5wbmciLCJpbWFnZTc4LnBuZyIsImltYWdlNzkucG5nIiwiaW1hZ2U4MC5wbmciLCJpbWFnZTgxLnBuZyIsImltYWdlODIucG5nIiwiaW1hZ2U4My5wbmciLCJpbWFnZTg0LnBuZyIsImltYWdlODUucG5nIiwiaW1hZ2U4Ni5wbmciLCJpbWFnZTg3LnBuZyIsImltYWdlODgucG5nIiwiaW1hZ2U4OS5wbmciLCJpbWFnZTkwLnBuZyIsImltYWdlOTEucG5nIiwiaW1hZ2U5Mi5wbmciLCJpbWFnZTkzLnBuZyIsImltYWdlOTQucG5nIiwiaW1hZ2U5NS5wbmciLCJpbWFnZTk2LnBuZyIsImltYWdlOTcucG5nIiwiaW1hZ2U5OC5wbmciLCJpbWFnZTk5LnBuZyIsImltYWdlMTAwLnBuZyIsImltYWdlMTAxLnBuZyIsImltYWdlMTAyLnBuZyIsImltYWdlMTAzLnBuZyIsImltYWdlMTA0LnBuZyIsImltYWdlMTA1LnBuZyIsImltYWdlMTA2LnBuZyIsImltYWdlMTA3LnBuZyIsImltYWdlMTA4LnBuZyIsImltYWdlMTA5LnBuZyIsImltYWdlMTEwLnBuZyIsImltYWdlMTExLnBuZyIsImltYWdlMTEyLnBuZyIsImltYWdlMTEzLnBuZyIsImltYWdlMTE0LnBuZyIsImltYWdlMTE1LnBuZyIsImltYWdlMTE2LnBuZyIsImltYWdlMTE3LnBuZyIsImltYWdlMTE4LnBuZyIsImltYWdlMTE5LnBuZyIsImltYWdlMTIwLnBuZyIsImltYWdlMTIxLnBuZyIsImltYWdlMTIyLnBuZyIsImltYWdlMTIzLnBuZyIsImltYWdlMTI0LnBuZyIsImltYWdlMTI1LnBuZyIsImltYWdlMTI2LnBuZyIsImltYWdlMTI3LnBuZyIsImltYWdlMTI4LnBuZyIsImltYWdlMTI5LnBuZyIsImltYWdlMTMwLnBuZyIsImltYWdlMTMxLnBuZyIsImltYWdlMTMyLnBuZyIsImltYWdlMTMzLnBuZyIsImltYWdlMTM0LnBuZyIsImltYWdlMTM1LnBuZyIsImltYWdlMTM2LnBuZyIsImltYWdlMTM3LnBuZyIsImltYWdlMTM4LnBuZyIsImltYWdlMTM5LnBuZyIsImltYWdlMTQwLnBuZyIsImltYWdlMTQxLnBuZyIsImltYWdlMTQyLnBuZyIsImltYWdlMTQzLnBuZyIsImltYWdlMTQ0LnBuZyIsImltYWdlMTQ1LnBuZyIsImltYWdlMTQ2LnBuZyIsImltYWdlMTQ3LnBuZyIsImltYWdlMTQ4LnBuZyIsImltYWdlMTQ5LnBuZyIsImltYWdlMTUwLnBuZyIsImltYWdlMTUxLnBuZyIsImltYWdlMTUyLnBuZyIsImltYWdlMTUzLnBuZyIsImltYWdlMTU0LnBuZyIsImltYWdlMTU1LnBuZyIsImltYWdlMTU2LnBuZyIsImltYWdlMTU3LnBuZyIsImltYWdlMTU4LnBuZyIsImltYWdlMTU5LnBuZyIsImltYWdlMTYwLnBuZyIsImltYWdlMTYxLnBuZyIsImltYWdlMTYyLnBuZyIsImltYWdlMTYzLnBuZyIsImltYWdlMTY0LnBuZyIsImltYWdlMTY1LnBuZyIsImltYWdlMTY2LnBuZyIsImltYWdlMTY3LnBuZyIsImltYWdlMTY4LnBuZyIsImltYWdlMTY5LnBuZyIsImltYWdlMTcwLnBuZyIsImltYWdlMTcxLnBuZyIsImltYWdlMTcyLnBuZyIsImltYWdlMTczLnBuZyIsImltYWdlMTc0LnBuZyIsImltYWdlMTc1LnBuZyIsImltYWdlMTc2LnBuZyIsImltYWdlMTc3LnBuZyIsImltYWdlMTc4LnBuZyIsImltYWdlMTc5LnBuZyIsImltYWdlMTgwLnBuZyIsImltYWdlMTgxLnBuZyIsImltYWdlMTgyLnBuZyIsImltYWdlMTgzLnBuZyIsImltYWdlMTg0LnBuZyIsImltYWdlMTg1LnBuZyIsImltYWdlMTg2LnBuZyIsImltYWdlMTg3LnBuZyIsImltYWdlMTg4LnBuZyIsImltYWdlMTg5LnBuZyIsImltYWdlMTkwLnBuZyIsImltYWdlMTkxLnBuZyIsImltYWdlMTkyLnBuZyIsImltYWdlMTkzLnBuZyIsImltYWdlMTk0LnBuZyIsImltYWdlMTk1LnBuZyIsImltYWdlMTk2LnBuZyIsImltYWdlMTk3LnBuZyIsImltYWdlMTk4LnBuZyIsImltYWdlMTk5LnBuZyIsImltYWdlMjAwLnBuZyIsImltYWdlMjAxLnBuZyIsImltYWdlMjAyLnBuZyIsImltYWdlMjAzLnBuZyIsImltYWdlMjA0LnBuZyIsImltYWdlMjA1LnBuZyIsImltYWdlMjA2LnBuZyIsImltYWdlMjA3LnBuZyIsImltYWdlMjA4LnBuZyIsImltYWdlMjA5LnBuZyIsImltYWdlMjEwLnBuZyIsImltYWdlMjExLnBuZyIsImltYWdlMjEyLnBuZyIsImltYWdlMjEzLnBuZyIsImltYWdlMjE0LnBuZyIsImltYWdlMjE1LnBuZyIsImltYWdlMjE2LnBuZyIsImltYWdlMjE3LnBuZyIsImltYWdlMjE4LnBuZyIsImltYWdlMjE5LnBuZyIsImltYWdlMjIwLnBuZyIsImltYWdlMjIxLnBuZyIsImltYWdlMjIyLnBuZyIsImltYWdlMjIzLnBuZyIsImltYWdlMjI0LnBuZyIsImltYWdlMjI1LnBuZyIsImltYWdlMjI2LnBuZyIsImltYWdlMjI3LnBuZyIsImltYWdlMjI4LnBuZyIsImltYWdlMjI5LnBuZyIsImltYWdlMjMwLnBuZyIsImltYWdlMjMxLnBuZyIsImltYWdlMjMyLnBuZyIsImltYWdlMjMzLnBuZyIsImltYWdlMjM0LnBuZyIsImltYWdlMjM1LnBuZyIsImltYWdlMjM2LnBuZyIsImltYWdlMjM3LnBuZyIsImltYWdlMjM4LnBuZyIsImltYWdlMjM5LnBuZyIsImltYWdlMjQwLnBuZyIsImltYWdlMjQxLnBuZyIsImltYWdlMjQyLnBuZyIsImltYWdlMjQzLnBuZyIsImltYWdlMjQ0LnBuZyIsImltYWdlMjQ1LnBuZyIsImltYWdlMjQ2LnBuZyIsImltYWdlMjQ3LnBuZyIsImltYWdlMjQ4LnBuZyIsImltYWdlMjQ5LnBuZyIsImltYWdlMjUwLnBuZyIsImltYWdlMjUxLnBuZyIsImltYWdlMjUyLnBuZyIsImltYWdlMjUzLnBuZyIsImltYWdlMjU0LnBuZyIsImltYWdlMjU1LnBuZyIsImltYWdlMjU2LnBuZyIsImltYWdlMjU3LnBuZyIsImltYWdlMjU4LnBuZyIsImltYWdlMjU5LnBuZyIsImltYWdlMjYwLnBuZyIsImltYWdlMjYxLnBuZyIsImltYWdlMjYyLnBuZyIsImltYWdlMjYzLnBuZyIsImltYWdlMjY0LnBuZyIsImltYWdlMjY1LnBuZyIsImltYWdlMjY2LnBuZyIsImltYWdlMjY3LnBuZyIsImltYWdlMjY4LnBuZyIsImltYWdlMjY5LnBuZyIsImltYWdlMjcwLnBuZyIsImltYWdlMjcxLnBuZyIsImltYWdlMjcyLnBuZyIsImltYWdlMjczLnBuZyIsImltYWdlMjc0LnBuZyIsImltYWdlMjc1LnBuZyIsImltYWdlMjc2LnBuZyIsImltYWdlMjc3LnBuZyIsImltYWdlMjc4LnBuZyIsImltYWdlMjc5LnBuZyIsImltYWdlMjgwLnBuZyIsImltYWdlMjgxLnBuZyIsImltYWdlMjgyLnBuZyIsImltYWdlMjgzLnBuZyIsImltYWdlMjg0LnBuZyIsImltYWdlMjg1LnBuZyIsImltYWdlMjg2LnBuZyIsImltYWdlMjg3LnBuZyIsImltYWdlMjg4LnBuZyIsImltYWdlMjg5LnBuZyIsImltYWdlMjkwLnBuZyIsImltYWdlMjkxLnBuZyIsImltYWdlMjkyLnBuZyIsImltYWdlMjkzLnBuZyIsImltYWdlMjk0LnBuZyIsImltYWdlMjk1LnBuZyIsImltYWdlMjk2LnBuZyIsImltYWdlMjk3LnBuZyIsImltYWdlMjk4LnBuZyIsImltYWdlMjk5LnBuZyIsImltYWdlMzAwLnBuZyIsImltYWdlMzAxLnBuZyIsImltYWdlMzAyLnBuZyIsImltYWdlMzAzLnBuZyIsImltYWdlMzA0LnBuZyIsImltYWdlMzA1LnBuZyIsImltYWdlMzA2LnBuZyIsImltYWdlMzA3LnBuZyIsImltYWdlMzA4LnBuZyIsImltYWdlMzA5LnBuZyIsImltYWdlMzEwLnBuZyIsImltYWdlMzExLnBuZyIsImltYWdlMzEyLnBuZyIsImltYWdlMzEzLnBuZyIsImltYWdlMzE0LnBuZyIsImltYWdlMzE1LnBuZyIsImltYWdlMzE2LnBuZyIsImltYWdlMzE3LnBuZyIsImltYWdlMzE4LnBuZyIsImltYWdlMzE5LnBuZyIsImltYWdlMzIwLnBuZyIsImltYWdlMzIxLnBuZyIsImltYWdlMzIyLnBuZyIsImltYWdlMzIzLnBuZyIsImltYWdlMzI0LnBuZyIsImltYWdlMzI1LnBuZyIsImltYWdlMzI2LnBuZyIsImltYWdlMzI3LnBuZyIsImltYWdlMzI4LnBuZyIsImltYWdlMzI5LnBuZyIsImltYWdlMzMwLnBuZyIsImltYWdlMzMxLnBuZyIsImltYWdlMzMyLnBuZyIsImltYWdlMzMzLnBuZyIsImltYWdlMzM0LnBuZyIsImltYWdlMzM1LnBuZyIsImltYWdlMzM2LnBuZyIsImltYWdlMzM3LnBuZyIsImltYWdlMzM4LnBuZyIsImltYWdlMzM5LnBuZyIsImltYWdlMzQwLnBuZyIsImltYWdlMzQxLnBuZyIsImltYWdlMzQyLnBuZyIsImltYWdlMzQzLnBuZyIsImltYWdlMzQ0LnBuZyIsImltYWdlMzQ1LnBuZyIsImltYWdlMzQ2LnBuZyIsImltYWdlMzQ3LnBuZyIsImltYWdlMzQ4LnBuZyIsImltYWdlMzQ5LnBuZyIsImltYWdlMzUwLnBuZyIsImltYWdlMzUxLnBuZyIsImltYWdlMzUyLnBuZyIsImltYWdlMzUzLnBuZyIsImltYWdlMzU0LnBuZyIsImltYWdlMzU1LnBuZyIsImltYWdlMzU2LnBuZyIsImltYWdlMzU3LnBuZyIsImltYWdlMzU4LnBuZyIsImltYWdlMzU5LnBuZyIsImltYWdlMzYwLnBuZyIsImltYWdlMzYxLnBuZyIsImltYWdlMzYyLnBuZyIsImltYWdlMzYzLnBuZyIsImltYWdlMzY0LnBuZyIsImltYWdlMzY1LnBuZyIsImltYWdlMzY2LnBuZyIsImltYWdlMzY3LnBuZyIsImltYWdlMzY4LnBuZyIsImltYWdlMzY5LnBuZyIsImltYWdlMzcwLnBuZyIsImltYWdlMzcxLnBuZyIsImltYWdlMzcyLnBuZyIsImltYWdlMzczLnBuZyIsImltYWdlMzc0LnBuZyIsImltYWdlMzc1LnBuZyIsImltYWdlMzc2LnBuZyIsImltYWdlMzc3LnBuZyIsImltYWdlMzc4LnBuZyIsImltYWdlMzc5LnBuZyIsImltYWdlMzgwLnBuZyIsImltYWdlMzgxLnBuZyIsImltYWdlMzgyLnBuZyIsImltYWdlMzgzLnBuZyIsImltYWdlMzg0LnBuZyIsImltYWdlMzg1LnBuZyIsImltYWdlMzg2LnBuZyIsImltYWdlMzg3LnBuZyIsImltYWdlMzg4LnBuZyIsImltYWdlMzg5LnBuZyIsImltYWdlMzkwLnBuZyIsImltYWdlMzkxLnBuZyIsImltYWdlMzkyLnBuZyIsImltYWdlMzkzLnBuZyIsImltYWdlMzk0LnBuZyIsImltYWdlMzk1LnBuZyIsImltYWdlMzk2LnBuZyIsImltYWdlMzk3LnBuZyIsImltYWdlMzk4LnBuZyIsImltYWdlMzk5LnBuZyIsImltYWdlNDAwLnBuZyIsImltYWdlNDAxLnBuZyIsImltYWdlNDAyLnBuZyIsImltYWdlNDAzLnBuZyIsImltYWdlNDA0LnBuZyIsImltYWdlNDA1LnBuZyIsImltYWdlNDA2LnBuZyIsImltYWdlNDA3LnBuZyIsImltYWdlNDA4LnBuZyIsImltYWdlNDA5LnBuZyIsImltYWdlNDEwLnBuZyIsImltYWdlNDExLnBuZyIsImltYWdlNDEyLnBuZyIsImltYWdlNDEzLnBuZyIsImltYWdlNDE0LnBuZyIsImltYWdlNDE1LnBuZyIsImltYWdlNDE2LnBuZyIsImltYWdlNDE3LnBuZyIsImltYWdlNDE4LnBuZyIsImltYWdlNDE5LnBuZyIsImltYWdlNDIwLnBuZyIsImltYWdlNDIxLnBuZyIsImltYWdlNDIyLnBuZyIsImltYWdlNDIzLnBuZyIsImltYWdlNDI0LnBuZyIsImltYWdlNDI1LnBuZyIsImltYWdlNDI2LnBuZyIsImltYWdlNDI3LnBuZyIsImltYWdlNDI4LnBuZyIsImltYWdlNDI5LnBuZyIsImltYWdlNDMwLnBuZyIsImltYWdlNDMxLnBuZyIsImltYWdlNDMyLnBuZyIsImltYWdlNDMzLnBuZyIsImltYWdlNDM0LnBuZyIsImltYWdlNDM1LnBuZyIsImltYWdlNDM2LnBuZyIsImltYWdlNDM3LnBuZyIsImltYWdlNDM4LnBuZyIsImltYWdlNDM5LnBuZyIsImltYWdlNDQwLnBuZyIsImltYWdlNDQxLnBuZyIsImltYWdlNDQyLnBuZyIsImltYWdlNDQzLnBuZyIsImltYWdlNDQ0LnBuZyIsImltYWdlNDQ1LnBuZyIsImltYWdlNDQ2LnBuZyIsImltYWdlNDQ3LnBuZyIsImltYWdlNDQ4LnBuZyIsImltYWdlNDQ5LnBuZyIsImltYWdlNDUwLnBuZyIsImltYWdlNDUxLnBuZyIsImltYWdlNDUyLnBuZyIsImltYWdlNDUzLnBuZyIsImltYWdlNDU0LnBuZyIsImltYWdlNDU1LnBuZyIsImltYWdlNDU2LnBuZyIsImltYWdlNDU3LnBuZyIsImltYWdlNDU4LnBuZyIsImltYWdlNDU5LnBuZyIsImltYWdlNDYwLnBuZyIsImltYWdlNDYxLnBuZyIsImltYWdlNDYyLnBuZyIsImltYWdlNDYzLnBuZyIsImltYWdlNDY0LnBuZyIsImltYWdlNDY1LnBuZyIsImltYWdlNDY2LnBuZyIsImltYWdlNDY3LnBuZyIsImltYWdlNDY4LnBuZyIsImltYWdlNDY5LnBuZyIsImltYWdlNDcwLnBuZyIsImltYWdlNDcxLnBuZyIsImltYWdlNDcyLnBuZyIsImltYWdlNDczLnBuZyIsImltYWdlNDc0LnBuZyIsImltYWdlNDc1LnBuZyIsImltYWdlNDc2LnBuZyIsImltYWdlNDc3LnBuZyIsImltYWdlNDc4LnBuZyIsImltYWdlNDc5LnBuZyIsImltYWdlNDgwLnBuZyIsImltYWdlNDgxLnBuZyIsImltYWdlNDgyLnBuZyIsImltYWdlNDgzLnBuZyIsImltYWdlNDg0LnBuZyIsImltYWdlNDg1LnBuZyIsImltYWdlNDg2LnBuZyIsImltYWdlNDg3LnBuZyIsImltYWdlNDg4LnBuZyIsImltYWdlNDg5LnBuZyIsImltYWdlNDkwLnBuZyIsImltYWdlNDkxLnBuZyIsImltYWdlNDkyLnBuZyIsImltYWdlNDkzLnBuZyIsImltYWdlNDk0LnBuZyIsImltYWdlNDk1LnBuZyIsImltYWdlNDk2LnBuZyIsImltYWdlNDk3LnBuZyIsImltYWdlNDk4LnBuZyIsImltYWdlNDk5LnBuZyIsImltYWdlNTAwLnBuZyIsImltYWdlNTAxLnBuZyIsImltYWdlNTAyLnBuZyIsImltYWdlNTAzLnBuZyIsImltYWdlNTA0LnBuZyIsImltYWdlNTA1LnBuZyIsImltYWdlNTA2LnBuZyIsImltYWdlNTA3LnBuZyIsImltYWdlNTA4LnBuZyIsImltYWdlNTA5LnBuZyIsImltYWdlNTEwLnBuZyIsImltYWdlNTExLnBuZyIsImltYWdlNTEyLnBuZyIsImltYWdlNTEzLnBuZyIsImltYWdlNTE0LnBuZyIsImltYWdlNTE1LnBuZyIsImltYWdlNTE2LnBuZyIsImltYWdlNTE3LnBuZyIsImltYWdlNTE4LnBuZyIsImltYWdlNTE5LnBuZyIsImltYWdlNTIwLnBuZyIsImltYWdlNTIxLnBuZyIsImltYWdlNTIyLnBuZyIsImltYWdlNTIzLnBuZyIsImltYWdlNTI0LnBuZyIsImltYWdlNTI1LnBuZyIsImltYWdlNTI2LnBuZyIsImltYWdlNTI3LnBuZyIsImltYWdlNTI4LnBuZyIsImltYWdlNTI5LnBuZyIsImltYWdlNTMwLnBuZyIsImltYWdlNTMxLnBuZyIsImltYWdlNTMyLnBuZyIsImltYWdlNTMzLnBuZyIsImltYWdlNTM0LnBuZyIsImltYWdlNTM1LnBuZyIsImltYWdlNTM2LnBuZyIsImltYWdlNTM3LnBuZyIsImltYWdlNTM4LnBuZyIsImltYWdlNTM5LnBuZyIsImltYWdlNTQwLnBuZyIsImltYWdlNTQxLnBuZyIsImltYWdlNTQyLnBuZyIsImltYWdlNTQzLnBuZyIsImltYWdlNTQ0LnBuZyIsImltYWdlNTQ1LnBuZyIsImltYWdlNTQ2LnBuZyIsImltYWdlNTQ3LnBuZyIsImltYWdlNTQ4LnBuZyIsImltYWdlNTQ5LnBuZyIsImltYWdlNTUwLnBuZyIsImltYWdlNTUxLnBuZyIsImltYWdlNTUyLnBuZyIsImltYWdlNTUzLnBuZyIsImltYWdlNTU0LnBuZyIsImltYWdlNTU1LnBuZyIsImltYWdlNTU2LnBuZyIsImltYWdlNTU3LnBuZyIsImltYWdlNTU4LnBuZyIsImltYWdlNTU5LnBuZyIsImltYWdlNTYwLnBuZyIsImltYWdlNTYxLnBuZyIsImltYWdlNTYyLnBuZyIsImltYWdlNTYzLnBuZyIsImltYWdlNTY0LnBuZyIsImltYWdlNTY1LnBuZyIsImltYWdlNTY2LnBuZyIsImltYWdlNTY3LnBuZyIsImltYWdlNTY4LnBuZyIsImltYWdlNTY5LnBuZyIsImltYWdlNTcwLnBuZyIsImltYWdlNTcxLnBuZyIsImltYWdlNTcyLnBuZyIsImltYWdlNTczLnBuZyIsImltYWdlNTc0LnBuZyIsImltYWdlNTc1LnBuZyIsImltYWdlNTc2LnBuZyIsImltYWdlNTc3LnBuZyIsImltYWdlNTc4LnBuZyIsImltYWdlNTc5LnBuZyIsImltYWdlNTgwLnBuZyIsImltYWdlNTgxLnBuZyIsImltYWdlNTgyLnBuZyIsImltYWdlNTgzLnBuZyIsImltYWdlNTg0LnBuZyIsImltYWdlNTg1LnBuZyIsImltYWdlNTg2LnBuZyIsImltYWdlNTg3LnBuZyIsImltYWdlNTg4LnBuZyIsImltYWdlNTg5LnBuZyIsImltYWdlNTkwLnBuZyIsImltYWdlNTkxLnBuZyIsImltYWdlNTkyLnBuZyIsImltYWdlNTkzLnBuZyIsImltYWdlNTk0LnBuZyIsImltYWdlNTk1LnBuZyIsImltYWdlNTk2LnBuZyIsImltYWdlNTk3LnBuZyIsImltYWdlNTk4LnBuZyIsImltYWdlNTk5LnBuZyIsImltYWdlNjAwLnBuZyIsImltYWdlNjAxLnBuZyIsImltYWdlNjAyLnBuZyIsImltYWdlNjAzLnBuZyIsImltYWdlNjA0LnBuZyIsImltYWdlNjA1LnBuZyIsImltYWdlNjA2LnBuZyIsImltYWdlNjA3LnBuZyIsImltYWdlNjA4LnBuZyIsImltYWdlNjA5LnBuZyIsImltYWdlNjEwLnBuZyIsImltYWdlNjExLnBuZyIsImltYWdlNjEyLnBuZyIsImltYWdlNjEzLnBuZyIsImltYWdlNjE0LnBuZyIsImltYWdlNjE1LnBuZyIsImltYWdlNjE2LnBuZyIsImltYWdlNjE3LnBuZyIsImltYWdlNjE4LnBuZyIsImltYWdlNjE5LnBuZyIsImltYWdlNjIwLnBuZyIsImltYWdlNjIxLnBuZyIsImltYWdlNjIyLnBuZyIsImltYWdlNjIzLnBuZyIsImltYWdlNjI0LnBuZyIsImltYWdlNjI1LnBuZyIsImltYWdlNjI2LnBuZyIsImltYWdlNjI3LnBuZyIsImltYWdlNjI4LnBuZyIsImltYWdlNjI5LnBuZyIsImltYWdlNjMwLnBuZyIsImltYWdlNjMxLnBuZyIsImltYWdlNjMyLnBuZyIsImltYWdlNjMzLnBuZyIsImltYWdlNjM0LnBuZyIsImltYWdlNjM1LnBuZyIsImltYWdlNjM2LnBuZyIsImltYWdlNjM3LnBuZyIsImltYWdlNjM4LnBuZyIsImltYWdlNjM5LnBuZyIsImltYWdlNjQwLnBuZyIsImltYWdlNjQxLnBuZyIsImltYWdlNjQyLnBuZyIsImltYWdlNjQzLnBuZyIsImltYWdlNjQ0LnBuZyIsImltYWdlNjQ1LnBuZyIsImltYWdlNjQ2LnBuZyIsImltYWdlNjQ3LnBuZyIsImltYWdlNjQ4LnBuZyIsImltYWdlNjQ5LnBuZyIsImltYWdlNjUwLnBuZyIsImltYWdlNjUxLnBuZyIsImltYWdlNjUyLnBuZyIsImltYWdlNjUzLnBuZyIsImltYWdlNjU0LnBuZyIsImltYWdlNjU1LnBuZyIsImltYWdlNjU2LnBuZyIsImltYWdlNjU3LnBuZyIsImltYWdlNjU4LnBuZyIsImltYWdlNjU5LnBuZyIsImltYWdlNjYwLnBuZyIsImltYWdlNjYxLnBuZyIsImltYWdlNjYyLnBuZyIsImltYWdlNjYzLnBuZyIsImltYWdlNjY0LnBuZyIsImltYWdlNjY1LnBuZyIsImltYWdlNjY2LnBuZyIsImltYWdlNjY3LnBuZyIsImltYWdlNjY4LnBuZyIsImltYWdlNjY5LnBuZyIsImltYWdlNjcwLnBuZyIsImltYWdlNjcxLnBuZyIsImltYWdlNjcyLnBuZyIsImltYWdlNjczLnBuZyIsImltYWdlNjc0LnBuZyIsImltYWdlNjc1LnBuZyIsImltYWdlNjc2LnBuZyIsImltYWdlNjc3LnBuZyIsImltYWdlNjc4LnBuZyIsImltYWdlNjc5LnBuZyIsImltYWdlNjgwLnBuZyIsImltYWdlNjgxLnBuZyIsImltYWdlNjgyLnBuZyIsImltYWdlNjgzLnBuZyIsImltYWdlNjg0LnBuZyIsImltYWdlNjg1LnBuZyIsImltYWdlNjg2LnBuZyIsImltYWdlNjg3LnBuZyIsImltYWdlNjg4LnBuZyIsImltYWdlNjg5LnBuZyIsImltYWdlNjkwLnBuZyIsImltYWdlNjkxLnBuZyIsImltYWdlNjkyLnBuZyIsImltYWdlNjkzLnBuZyIsImltYWdlNjk0LnBuZyIsImltYWdlNjk1LnBuZyIsImltYWdlNjk2LnBuZyIsImltYWdlNjk3LnBuZyIsImltYWdlNjk4LnBuZyIsImltYWdlNjk5LnBuZyIsImltYWdlNzAwLnBuZyIsImltYWdlNzAxLnBuZyIsImltYWdlNzAyLnBuZyIsImltYWdlNzAzLnBuZyIsImltYWdlNzA0LnBuZyIsImltYWdlNzA1LnBuZyIsImltYWdlNzA2LnBuZyIsImltYWdlNzA3LnBuZyIsImltYWdlNzA4LnBuZyIsImltYWdlNzA5LnBuZyIsImltYWdlNzEwLnBuZyIsImltYWdlNzExLnBuZyIsImltYWdlNzEyLnBuZyIsImltYWdlNzEzLnBuZyIsImltYWdlNzE0LnBuZyIsImltYWdlNzE1LnBuZyIsImltYWdlNzE2LnBuZyIsImltYWdlNzE3LnBuZyIsImltYWdlNzE4LnBuZyIsImltYWdlNzE5LnBuZyIsImltYWdlNzIwLnBuZyIsImltYWdlNzIxLnBuZyIsImltYWdlNzIyLnBuZyIsImltYWdlNzIzLnBuZyIsImltYWdlNzI0LnBuZyIsImltYWdlNzI1LnBuZyIsImltYWdlNzI2LnBuZyIsImltYWdlNzI3LnBuZyIsImltYWdlNzI4LnBuZyIsImltYWdlNzI5LnBuZyIsImltYWdlNzMwLnBuZyIsImltYWdlNzMxLnBuZyIsImltYWdlNzMyLnBuZyIsImltYWdlNzMzLnBuZyIsImltYWdlNzM0LnBuZyIsImltYWdlNzM1LnBuZyIsImltYWdlNzM2LnBuZyIsImltYWdlNzM3LnBuZyIsImltYWdlNzM4LnBuZyIsImltYWdlNzM5LnBuZyIsImltYWdlNzQwLnBuZyIsImltYWdlNzQxLnBuZyIsImltYWdlNzQyLnBuZyIsImltYWdlNzQzLnBuZyIsImltYWdlNzQ0LnBuZyIsImltYWdlNzQ1LnBuZyIsImltYWdlNzQ2LnBuZyIsImltYWdlNzQ3LnBuZyIsImltYWdlNzQ4LnBuZyIsImltYWdlNzQ5LnBuZyIsImltYWdlNzUwLnBuZyIsImltYWdlNzUxLnBuZyIsImltYWdlNzUyLnBuZyIsImltYWdlNzUzLnBuZyIsImltYWdlNzU0LnBuZyIsImltYWdlNzU1LnBuZyIsImltYWdlNzU2LnBuZyIsImltYWdlNzU3LnBuZyIsImltYWdlNzU4LnBuZyIsImltYWdlNzU5LnBuZyIsImltYWdlNzYwLnBuZyIsImltYWdlNzYxLnBuZyIsImltYWdlNzYyLnBuZyIsImltYWdlNzYzLnBuZyIsImltYWdlNzY0LnBuZyIsImltYWdlNzY1LnBuZyIsImltYWdlNzY2LnBuZyIsImltYWdlNzY3LnBuZyIsImltYWdlNzY4LnBuZyIsImltYWdlNzY5LnBuZyIsImltYWdlNzcwLnBuZyIsImltYWdlNzcxLnBuZyIsImltYWdlNzcyLnBuZyIsImltYWdlNzczLnBuZyIsImltYWdlNzc0LnBuZyIsImltYWdlNzc1LnBuZyIsImltYWdlNzc2LnBuZyIsImltYWdlNzc3LnBuZyIsImltYWdlNzc4LnBuZyIsImltYWdlNzc5LnBuZyIsImltYWdlNzgwLnBuZyIsImltYWdlNzgxLnBuZyIsImltYWdlNzgyLnBuZyIsImltYWdlNzgzLnBuZyIsImltYWdlNzg0LnBuZyIsImltYWdlNzg1LnBuZyIsImltYWdlNzg2LnBuZyIsImltYWdlNzg3LnBuZyIsImltYWdlNzg4LnBuZyIsImltYWdlNzg5LnBuZyIsImltYWdlNzkwLnBuZyIsImltYWdlNzkxLnBuZyIsImltYWdlNzkyLnBuZyIsImltYWdlNzkzLnBuZyIsImltYWdlNzk0LnBuZyIsImltYWdlNzk1LnBuZyIsImltYWdlNzk2LnBuZyIsImltYWdlNzk3LnBuZyIsImltYWdlNzk4LnBuZyIsImltYWdlNzk5LnBuZyIsImltYWdlODAwLnBuZyIsImltYWdlODAxLnBuZyIsImltYWdlODAyLnBuZyIsImltYWdlODAzLnBuZyIsImltYWdlODA0LnBuZyIsImltYWdlODA1LnBuZyIsImltYWdlODA2LnBuZyIsImltYWdlODA3LnBuZyIsImltYWdlODA4LnBuZyIsImltYWdlODA5LnBuZyIsImltYWdlODEwLnBuZyIsImltYWdlODExLnBuZyIsImltYWdlODEyLnBuZyIsImltYWdlODEzLnBuZyIsImltYWdlODE0LnBuZyIsImltYWdlODE1LnBuZyIsImltYWdlODE2LnBuZyIsImltYWdlODE3LnBuZyIsImltYWdlODE4LnBuZyIsImltYWdlODE5LnBuZyIsImltYWdlODIwLnBuZyIsImltYWdlODIxLnBuZyIsImltYWdlODIyLnBuZyIsImltYWdlODIzLnBuZyIsImltYWdlODI0LnBuZyIsImltYWdlODI1LnBuZyIsImltYWdlODI2LnBuZyIsImltYWdlODI3LnBuZyIsImltYWdlODI4LnBuZyIsImltYWdlODI5LnBuZyIsImltYWdlODMwLnBuZyIsImltYWdlODMxLnBuZyIsImltYWdlODMyLnBuZyIsImltYWdlODMzLnBuZyIsImltYWdlODM0LnBuZyIsImltYWdlODM1LnBuZyIsImltYWdlODM2LnBuZyIsImltYWdlODM3LnBuZyIsImltYWdlODM4LnBuZyIsImltYWdlODM5LnBuZyIsImltYWdlODQwLnBuZyIsImltYWdlODQxLnBuZyIsImltYWdlODQyLnBuZyIsImltYWdlODQzLnBuZyIsImltYWdlODQ0LnBuZyIsImltYWdlODQ1LnBuZyIsImltYWdlODQ2LnBuZyIsImltYWdlODQ3LnBuZyIsImltYWdlODQ4LnBuZyIsImltYWdlODQ5LnBuZyIsImltYWdlODUwLnBuZyIsImltYWdlODUxLnBuZyIsImltYWdlODUyLnBuZyIsImltYWdlODUzLnBuZyIsImltYWdlODU0LnBuZyIsImltYWdlODU1LnBuZyIsImltYWdlODU2LnBuZyIsImltYWdlODU3LnBuZyIsImltYWdlODU4LnBuZyIsImltYWdlODU5LnBuZyIsImltYWdlODYwLnBuZyIsImltYWdlODYxLnBuZyIsImltYWdlODYyLnBuZyIsImltYWdlODYzLnBuZyIsImltYWdlODY0LnBuZyIsImltYWdlODY1LnBuZyIsImltYWdlODY2LnBuZyIsImltYWdlODY3LnBuZyIsImltYWdlODY4LnBuZyIsImltYWdlODY5LnBuZyIsImltYWdlODcwLnBuZyIsImltYWdlODcxLnBuZyIsImltYWdlODcyLnBuZyIsImltYWdlODczLnBuZyIsImltYWdlODc0LnBuZyIsImltYWdlODc1LnBuZyIsImltYWdlODc2LnBuZyIsImltYWdlODc3LnBuZyIsImltYWdlODc4LnBuZyIsImltYWdlODc5LnBuZyIsImltYWdlODgwLnBuZyIsImltYWdlODgxLnBuZyIsImltYWdlODgyLnBuZyIsImltYWdlODgzLnBuZyIsImltYWdlODg0LnBuZyIsImltYWdlODg1LnBuZyIsImltYWdlODg2LnBuZyIsImltYWdlODg3LnBuZyIsImltYWdlODg4LnBuZyIsImltYWdlODg5LnBuZyIsImltYWdlODkwLnBuZyIsImltYWdlODkxLnBuZyIsImltYWdlODkyLnBuZyIsImltYWdlODkzLnBuZyIsImltYWdlODk0LnBuZyIsImltYWdlODk1LnBuZyIsImltYWdlODk2LnBuZyIsImltYWdlODk3LnBuZyIsImltYWdlODk4LnBuZyIsImltYWdlODk5LnBuZyIsImltYWdlOTAwLnBuZyIsImltYWdlOTAxLnBuZyIsImltYWdlOTAyLnBuZyIsImltYWdlOTAzLnBuZyIsImltYWdlOTA0LnBuZyIsImltYWdlOTA1LnBuZyIsImltYWdlOTA2LnBuZyIsImltYWdlOTA3LnBuZyIsImltYWdlOTA4LnBuZyIsImltYWdlOTA5LnBuZyIsImltYWdlOTEwLnBuZyIsImltYWdlOTExLnBuZyIsImltYWdlOTEyLnBuZyIsImltYWdlOTEzLnBuZyIsImltYWdlOTE0LnBuZyIsImltYWdlOTE1LnBuZyIsImltYWdlOTE2LnBuZyIsImltYWdlOTE3LnBuZyIsImltYWdlOTE4LnBuZyIsImltYWdlOTE5LnBuZyIsImltYWdlOTIwLnBuZyIsImltYWdlOTIxLnBuZyIsImltYWdlOTIyLnBuZyIsImltYWdlOTIzLnBuZyIsImltYWdlOTI0LnBuZyIsImltYWdlOTI1LnBuZyIsImltYWdlOTI2LnBuZyIsImltYWdlOTI3LnBuZyIsImltYWdlOTI4LnBuZyIsImltYWdlOTI5LnBuZyIsImltYWdlOTMwLnBuZyIsImltYWdlOTMxLnBuZyIsImltYWdlOTMyLnBuZyIsImltYWdlOTMzLnBuZyIsImltYWdlOTM0LnBuZyIsImltYWdlOTM1LnBuZyIsImltYWdlOTM2LnBuZyIsImltYWdlOTM3LnBuZyIsImltYWdlOTM4LnBuZyIsImltYWdlOTM5LnBuZyIsImltYWdlOTQwLnBuZyIsImltYWdlOTQxLnBuZyIsImltYWdlOTQyLnBuZyIsImltYWdlOTQzLnBuZyIsImltYWdlOTQ0LnBuZyIsImltYWdlOTQ1LnBuZyIsImltYWdlOTQ2LnBuZyIsImltYWdlOTQ3LnBuZyIsImltYWdlOTQ4LnBuZyIsImltYWdlOTQ5LnBuZyIsImltYWdlOTUwLnBuZyIsImltYWdlOTUxLnBuZyIsImltYWdlOTUyLnBuZyIsImltYWdlOTUzLnBuZyIsImltYWdlOTU0LnBuZyIsImltYWdlOTU1LnBuZyIsImltYWdlOTU2LnBuZyIsImltYWdlOTU3LnBuZyIsImltYWdlOTU4LnBuZyIsImltYWdlOTU5LnBuZyIsImltYWdlOTYwLnBuZyIsImltYWdlOTYxLnBuZyIsImltYWdlOTYyLnBuZyIsImltYWdlOTYzLnBuZyIsImltYWdlOTY0LnBuZyIsImltYWdlOTY1LnBuZyIsImltYWdlOTY2LnBuZyIsImltYWdlOTY3LnBuZyIsImltYWdlOTY4LnBuZyIsImltYWdlOTY5LnBuZyIsImltYWdlOTcwLnBuZyIsImltYWdlOTcxLnBuZyIsImltYWdlOTcyLnBuZyIsImltYWdlOTczLnBuZyIsImltYWdlOTc0LnBuZyIsImltYWdlOTc1LnBuZyIsImltYWdlOTc2LnBuZyIsImltYWdlOTc3LnBuZyIsImltYWdlOTc4LnBuZyIsImltYWdlOTc5LnBuZyIsImltYWdlOTgwLnBuZyIsImltYWdlOTgxLnBuZyIsImltYWdlOTgyLnBuZyIsImltYWdlOTgzLnBuZyIsImltYWdlOTg0LnBuZyIsImltYWdlOTg1LnBuZyIsImltYWdlOTg2LnBuZyIsImltYWdlOTg3LnBuZyIsImltYWdlOTg4LnBuZyIsImltYWdlOTg5LnBuZyIsImltYWdlOTkwLnBuZyIsImltYWdlOTkxLnBuZyIsImltYWdlOTkyLnBuZyIsImltYWdlOTkzLnBuZyIsImltYWdlOTk0LnBuZyIsImltYWdlOTk1LnBuZyIsImltYWdlOTk2LnBuZyIsImltYWdlOTk3LnBuZyIsImltYWdlOTk4LnBuZyIsImltYWdlOTk5LnBuZyJdLCJpYXQiOjE1MTYyMzkwMjJ9.KGrocKdxHn_ZCkgfl5SAbKxCm8tbqVOBslU_x3SrYAg" rel="noopener noreferrer"&gt;has 1000 files&lt;/a&gt; the JWT length changes from 239 characters to 20,057 - and that’s considering a simple file name. With the full path, it’s even longer. Additionally, a JWT created during the authentication phase doesn’t include all the necessary information required to make the policy decision -  especially if you are using a vendor like Auth0 to authenticate. In addition, storing data in JWTs means we have to refresh the token (read as login/logout) every time we want to update the data. &lt;/p&gt;

&lt;p&gt;The ugly:&lt;br&gt;
You might think it’s a good idea to start with JWTs because you don’t have a lot of data - as time goes by the amount of data grows exponentially, and the situation easily spirals out of control, with an enormous amount of JWTs floating around in each request. &lt;/p&gt;

&lt;p&gt;Bottom-line:&lt;br&gt;
JWTs are ideal for simple identity-related data, and in general, it’s best to think of the claims and data in the JWT as hints about identity (given by the Identity-Management and Authentication layers) rather than verbatim data for authorization.&lt;/p&gt;

&lt;p&gt;&lt;br&gt;
&lt;a&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;
  
  
  2. Overload input for OPA within the query:
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpbanaskj2vd000gw0io6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpbanaskj2vd000gw0io6.png" alt="Overload input for OPA within the query" width="654" height="630"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Another option is to attach input for every policy query to OPA, adding the relevant data to it.  &lt;br&gt;
It will look something like this in python pseudocode wrapping OPA:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def delete_image(user_id, image_id):
    policy_json_data = {}
    policy_json_data[“user_roles”] = get_user_roles(user_id) # returns list of roles like [“editor”]
    policy_json_data[”user_images”] = get_user_images(user_id) # returns list of images [“img.png”]

# sends request that looks like this:
# localhost:8181 -i -d ‘{"roles": ["pro"], "related_images": ["image0.png", "image1.png"], image_id: “image2.png”}’ -H 'Content-Type: application/json'
# and returns true / false
    permitted = check_opa_policy(policy_json_data, “delete”, image_id) 
    if not permitted:
        raise(AuthorizationError)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The good:&lt;br&gt;
Using this method is simple, and it ensures that only the relevant data is cherry-picked for each query sent, thus avoiding loading/storing a lot of data in OPA.&lt;br&gt;
 &lt;br&gt;
The bad:&lt;br&gt;
This method prevents us from following one of the most important best practices in building authorization - decoupling policy and code. As our code now has to take on the responsibility of tailoring the data for OPA. Having policy and code mixed together in one layer creates a situation where we struggle to upgrade, add capabilities and monitor the code overall as it is replicated between different microservices. Each change would require us to refactor large areas of code that only drift further from one another as these microservices develop.&lt;/p&gt;

&lt;p&gt;The ugly:&lt;br&gt;
Having so much code repetition is an antithesis to the &lt;a href="https://en.wikipedia.org/wiki/Don%27t_repeat_yourself" rel="noopener noreferrer"&gt;DRY&lt;/a&gt; principle - creating a multitude of complications and difficulties as our application evolves. Considering the example code above for instance, a very similar code will be written to delete_image, update_image, and get_image.&lt;/p&gt;

&lt;p&gt;Bottom-line:&lt;br&gt;
In general, it is best to leave this method for simple cases or to augment more advanced cases with cherry-picking.&lt;/p&gt;

&lt;p&gt;&lt;br&gt;
&lt;a&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;
  
  
  3. Polling for data using Bundles
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feg63nn96nxolj31grutf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feg63nn96nxolj31grutf.png" alt="Polling for data using Bundles" width="654" height="630"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The bundle feature periodically checks and downloads policy bundles from a centralized server, which can include both data and policies. An example of a simple way to implement this solution would be running an Nginx container that serves the bundle files and configuring OPA to fetch data from it (using s3 buckets is also a common pattern). The configuration for OPA will be as follows:&lt;br&gt;
&lt;br&gt;
 &lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;services:
  nginx:
    url: https://my-nginx.example.com
    credentials:
      bearer:
        token: dGVzdGluZzp0ZXN0aW5n
        scheme: Basic

bundles:
  authz:
    service: nginx
    resource: /bundle.tar.gz
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The good:&lt;br&gt;
It allows you to load large amounts of data (much larger than the 2 previous methods), it has a delta bundle feature that lets you sync only new data (but not policy), it lets you have one source of truth, and it is more readable than JWTs.&lt;br&gt;
 &lt;br&gt;
The bad:&lt;br&gt;
Using bundles doesn’t cut it when we have data that changes rapidly, as it requires triggering a full policy update for every small change - Making this a very inefficient process.&lt;/p&gt;

&lt;p&gt;The ugly:&lt;br&gt;
Even with the new delta bundle feature, you still need to manage and create the bundles on your own, and it works with polling which isn’t real-time.&lt;/p&gt;

&lt;p&gt;In addition, being dependent on a polling interval means you have to choose between rapid polling which can result in high costs or slow polling which can lead to delays and risk of inconsistency.&lt;/p&gt;

&lt;p&gt;The bottom line:&lt;br&gt;
For cases where updates to data mainly come as part of the CI/CD cycle, bundles are a great option.  Bundles can also work well for static or rather static applications. For modern dynamic applications, this option might be too slow/inefficient on its own. &lt;/p&gt;

&lt;p&gt;&lt;br&gt;
&lt;a&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;
  
  
  4. Pushing data into OPA using the API
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft9irp12udfrrqxgha8ha.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft9irp12udfrrqxgha8ha.png" alt="Pushing data into OPA using the API" width="654" height="630"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can also push policy data into OPA with an API request - this approach is similar in most aspects to the bundle API, except it allows you to optimize for update latency and network traffic. It will look something like this in python pseudo-code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def send_user_update_to_opa():
    requests.put(f”{opa_url}/users”, params={users: [user1,user2]})

def callback_on_new_user():
    all_users = get_all_users()
    send_update_to_opa(all_users)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, we are updating the user list of OPA for each callback on new user creation.&lt;/p&gt;

&lt;p&gt;The good:&lt;br&gt;
This way you don’t need to load the entire bundle at every update, you can also update part of it, which is much more performant in terms of memory and network usage - as well as giving you more control of how you manage distributed data into OPA.&lt;/p&gt;

&lt;p&gt;The bad:&lt;br&gt;
Applying this method to import new kinds of data from different data sources is going to require a continuous effort of writing enormous amounts of code.&lt;/p&gt;

&lt;p&gt;The ugly:&lt;br&gt;
This method requires continuous maintenance - you can’t just set it up and forget about it. If left abandoned, this code will very quickly become obsolete. &lt;/p&gt;

&lt;p&gt;The bottom line: &lt;br&gt;
Great way to load data into OPA in a dynamic fashion, but requires a lot of development and administration in all but very simple cases.&lt;/p&gt;

&lt;p&gt;&lt;br&gt;
&lt;a&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;
  
  
  5. Pulling data using OPA during Policy Evaluation
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu433tzpk0er2ekgqw5rc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu433tzpk0er2ekgqw5rc.png" alt="Pulling data using OPA during Policy Evaluation" width="654" height="630"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;OPA includes a function (&lt;code&gt;http.send()&lt;/code&gt;) that allows it to reach out to external HTTP servers during evaluation and request additional data. It will look something like this in Rego pseudo-code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
default allow = false
 
allow = true {
    input.method == "GET"
    input.path = ["getSalary", user]
    managers := http.send(get_managers_url)
    managers := managers[input.user][_]
    contains(managers, user)
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can see the call to http.send(get_managers_url) that returns the list of the managers to help evaluate the policy. Similarly, you can embed more functions into OPA as a plugin to fetch data as part of a query from other sources.&lt;/p&gt;

&lt;p&gt;The good:&lt;br&gt;
This is a solid option to use when you have a very large volume of data that is required to make permission decisions, and you cannot load it all into OPA.&lt;/p&gt;

&lt;p&gt;The bad:&lt;br&gt;
Using this method puts a strain on OPA as it always comes with network latency that slows all of your policy evaluations. Additionally, this method is prone to network errors.  &lt;/p&gt;

&lt;p&gt;The ugly:&lt;br&gt;
Error handling with rego isn’t simple at all, and relying on this feature can lead to some &lt;a href="https://github.com/open-policy-agent/opa/pull/2763" rel="noopener noreferrer"&gt;frustrating results&lt;/a&gt;. While OPA and Rego can be used to evaluate policies very quickly, you may want to avoid adding more logic than you need.&lt;/p&gt;

&lt;p&gt;The bottom line: &lt;br&gt;
This is a great way to load data into OPA in a highly dynamic way without writing a lot of code. That being said, this solution is not applicable when the relevant data requires parsing or edge case handling, which Rego lacks. &lt;/p&gt;

&lt;p&gt;&lt;br&gt;
&lt;a&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  6. OPAL (Open Policy Administration Layer):
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdd6vutu871xkn5ayvt27.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdd6vutu871xkn5ayvt27.png" alt="OPAL Open Policy Administration Layer" width="654" height="630"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;OPAL &lt;a href="https://github.com/permitio/opal" rel="noopener noreferrer"&gt;is an open-source project&lt;/a&gt; for administering authorization and access control for OPA. OPAL responds to policy and data changes, pushes live updates to OPA agents, and thus brings open policy up to the speed needed by live applications.&lt;/p&gt;

&lt;p&gt;To run OPAL with OPA you can simply &lt;a href="https://github.com/permitio/opal/blob/master/docs/HOWTO/get_started_with_opal_docker_compose_tutorial.md" rel="noopener noreferrer"&gt;use the Docker example&lt;/a&gt;. Send an &lt;a href="https://github.com/permitio/opal/blob/master/docs/HOWTO/trigger_data_updates.md" rel="noopener noreferrer"&gt;update to OPAL on every change in your data&lt;/a&gt; or connect your data source's webhook with OPAL and let OPAL stream the updates to OPA.&lt;/p&gt;

&lt;p&gt;The good:&lt;br&gt;
OPAL includes live updates and Git tracking (GitOps) and saves you the hassle of having to write all the code by yourself like in the ‘Pushing Data with API’ option.&lt;/p&gt;

&lt;p&gt;The bad:&lt;br&gt;
OPAL is a fairly new library, it might take some time to learn and some work to integrate into your project.&lt;/p&gt;

&lt;p&gt;The ugly:&lt;br&gt;
First of all, OPAL is beautiful (But being one of the contributors to this open source project I might be biased). That being said, the architecture can be a bit more complicated than bundle server/JWTs, so you might need to take your time and make sure you understand it.&lt;/p&gt;

&lt;p&gt;The bottom line:&lt;br&gt;
OPAL is inspired by the way companies like Netflix work with OPA, but it requires some work to set up. Simple applications will do better with one of the other methods, but for full modern applications, OPAL is probably the more robust/reliable option. &lt;/p&gt;



&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;There are various methods to build data fetching mechanisms - each of them having their own pros and cons. &lt;/p&gt;

&lt;p&gt;Some of these methods (Including data in JWT tokens and using Overload input for OPA within the query) could only prove useful in simple cases, some (Polling for data using Bundles) lack effectiveness in dynamic applications. Pushing data with API is a good solution to load data into OPA in a dynamic fashion while requiring a lot of development and administration, and Pulling data using OPA during Policy Evaluation is not applicable when the relevant data requires parsing or edge case handling. OPAL has the advantage of being a more robust/reliable solution, but it requires you to adopt new open-source-based technology.&lt;br&gt;
The most important thing to take from this review is understanding the complexities and challenges of building data fetching mechanisms correctly, and understanding that every method has its pros and cons. &lt;br&gt;
⁠&lt;br&gt;
⁠Still not sure which method is the right one for you and your architecture? Need someone to brainstorm with? Don’t be shy - reach out to us on our &lt;a href="https://bit.ly/permitcommunity" rel="noopener noreferrer"&gt;Slack community&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>opa</category>
      <category>authorization</category>
      <category>tutorial</category>
      <category>authz</category>
    </item>
    <item>
      <title>A Guide for an Awesome Custom Auth0 Universal login</title>
      <dc:creator>OdedBD</dc:creator>
      <pubDate>Wed, 26 Jan 2022 10:13:52 +0000</pubDate>
      <link>https://dev.to/permit_io/a-guide-for-an-awesome-custom-auth0-universal-login-100h</link>
      <guid>https://dev.to/permit_io/a-guide-for-an-awesome-custom-auth0-universal-login-100h</guid>
      <description>&lt;p&gt;Your login and sign-up screens are the gateway to your app - the first thing a person sees before entering your actual application. So, they better look amazing, if you want an awesome app.&lt;/p&gt;

&lt;p&gt;While creating our own login screen at Permit.io, I had to review and collect data from multiple different guides, so I finally decided to incorporate them into one unified guide that will help you transform your own login screen completely.&lt;/p&gt;

&lt;p&gt;In this guide, we will cover:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;5 reasons why you should customize the default Auth0 login&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;How to edit the default Auth0 login template&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;How to edit the Auth0 default title and description&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Which customization features are yet to be available&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Using Auth0 authentication has its advantages - It’s fast, secure, and highly functional. &lt;br&gt;
That being said, you can’t have the first thing your user sees when entering your app look like this: &lt;/p&gt;

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

&lt;p&gt;&lt;br&gt;
&lt;a&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  5 reasons why you should customize the default Auth0 login -
&lt;/h2&gt;

&lt;p&gt;While functional, using the default Auth0 login screen has some key issues:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;While the login / sign-up screen is a crucial step in a user’s onboarding process, the default Auth0 login screen lacks some important elements - The company name is there, but the &lt;strong&gt;overall look is different&lt;/strong&gt;. This makes the login screen seem like a &lt;strong&gt;foreign entity inside your application&lt;/strong&gt;. And that’s not a good user experience. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The default option Auth0 provides in login through an &lt;strong&gt;external domain&lt;/strong&gt; that belongs to Auth0, meaning each time someone wants to log in to use your application they are &lt;strong&gt;redirected to a domain outside that of your company&lt;/strong&gt;. Your users might have no idea what Auth0 is, or why they are referred to this external website to provide their login information. This looks both unprofessional and unsecure. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;This sense of unfamiliarity creates another issue: because the login screen doesn’t look like the rest of your company’s user interface, and it is based on a domain outside your company, &lt;strong&gt;it can be easily interpreted by the user as a &lt;a href="https://auth0.com/blog/phishing-attacks-with-auth0-facts-first/" rel="noopener noreferrer"&gt;phishing attack&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The message displayed reads: “Log in to ‘Company Name’ to continue to ‘Application Name’”. Not only is this not the most inviting message, changing it is no trivial task (As we will see later on).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The login interface uses only a small percentage of your screen, the rest of it being just one color, making it look quite dull and uninviting on one of the most important screens in your entire app. &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;While the good news is that most of these features are customizable, the bad news is that implementing these customizations is no easy feat, and far from intuitive. Hence this guide 😉&lt;br&gt;
&lt;br&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  What can we do about this?
&lt;/h2&gt;

&lt;p&gt;Overcoming these issues took me a while, but we were very pleased with the end result:&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;So how did we get here? Let’s review the steps:&lt;/strong&gt;&lt;/p&gt;



&lt;h2&gt;
  
  
  1. Enabling custom domains
&lt;/h2&gt;

&lt;p&gt;As we have stated before, having your login/signup based in a domain outside your company creates various issues. Apart from that, Auth0 only allows you to customize your login screen by using a custom domain - which is a paid feature. &lt;/p&gt;

&lt;p&gt;To do this - &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Choose the correct tenant (most likely production).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;In the left sidebar go to &lt;strong&gt;Branding&lt;/strong&gt; &amp;gt; &lt;strong&gt;Custom Domains&lt;/strong&gt;.&lt;br&gt;
(If you haven’t upgraded your plan to include custom domain support, you will need to do that first).&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Approve your custom domain through the instructions provided by Auth0 to prove that you actually own it (This includes adding some TXT entries to the domain).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;This is what an approved custom domain should look like (notice the &lt;strong&gt;ready&lt;/strong&gt; status):&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;&lt;br&gt;
&lt;a&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  2. Editing the login template
&lt;/h2&gt;

&lt;p&gt;Now that we have a custom domain, we can get to editing the login screen itself. &lt;/p&gt;

&lt;p&gt;If you check out &lt;a href="https://auth0.com/docs/brand-and-customize/universal-login-page-templates" rel="noopener noreferrer"&gt;Auth0’s documentation&lt;/a&gt; you will notice they suggest using POST requests to update the template. This means posting all of the code for the entire page every time we want to make the smallest of changes. That can be a huge hassle. &lt;/p&gt;

&lt;p&gt;To overcome this issue, I used &lt;a href="https://github.com/auth0/auth0-cli" rel="noopener noreferrer"&gt;Auth0 CLI&lt;/a&gt; (That’s still in beta, but works &lt;em&gt;almost&lt;/em&gt; perfectly) which utilizes &lt;a href="https://storybook.js.org/" rel="noopener noreferrer"&gt;Storybook&lt;/a&gt;. Auth0 CLI allows you to edit the login template from your code editor while previewing those changes in Storybook as you go along.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How to do this:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Download Auth0 CLI:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;On Mac:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;brew tap auth0/auth0-cli &amp;amp;&amp;amp; brew install auth0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On Linux:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;brew tap auth0/auth0-cli &amp;amp;&amp;amp; brew install auth0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On windows (With Scoop):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;scoop bucket add auth0 https://github.com/auth0/scoop-auth0-cli.git 
⁠scoop install auth0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check &lt;a href="https://github.com/auth0/auth0-cli" rel="noopener noreferrer"&gt;this link&lt;/a&gt; for more options.&lt;br&gt;
⁠&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Login to your account using the following command: &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;auth0 login&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Run the following command: &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;auth0 branding templates update&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This will open your default code editor (I recommend &lt;a href="https://stackoverflow.com/a/36644561/1037613" rel="noopener noreferrer"&gt;setting VSCode as your default editor&lt;/a&gt;), and a Storybook window in your browser, previewing the current state of your login screen. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When you make changes in your code editor, you see them updated live in the Storybook preview window. &lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;&lt;em&gt;This is how the StoryBook preview looks like&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Remember to add &lt;code&gt;{%- auth0:head -%}&lt;/code&gt; in the HTML head tag 
⁠and &lt;code&gt;{%- auth0:widget -%}&lt;/code&gt; where you want the Auth0 widget to be injected. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is an example of a basic template that displays the Auth0 login, (we also shared our full template at the end of this guide):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;⁠html
&amp;lt;!DOCTYPE html&amp;gt;&amp;lt;html&amp;gt;
  &amp;lt;head&amp;gt;
    {%- auth0:head -%}
  &amp;lt;/head&amp;gt;
  &amp;lt;body&amp;gt;
    {%- auth0:widget -%}
  &amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;When you close the editor, Auth0 CLI will ask you if you want to update the login template. &lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Approve, and you’re done!&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Important note:&lt;/strong&gt;&lt;br&gt;
The authentication widget previewed on Storybook is not identical to the actual one that is going to appear on your website. These could also display a bit differently on mobile/different screens - so make sure to recheck everything in your real environment after updating your template. &lt;/p&gt;

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

&lt;p&gt;&lt;em&gt;Note the Storybook preview (Left) vs. the actual version (right).&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;⁠&lt;br&gt;
&lt;a&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Editing Auth0 widget default title and description
&lt;/h2&gt;

&lt;p&gt;⁠In this part, I’ll explain how to change the default text templates provided in the Auth0 login screen through API management. The default text will look like this:&lt;/p&gt;

&lt;p&gt;Log in to `Company Name’ to continue to ‘Application Name’&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;To do this:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;First, you will need to get your API management token: Go to
&lt;strong&gt;Applications&lt;/strong&gt; &amp;gt; &lt;strong&gt;APIs&lt;/strong&gt;, click on Auth0 Management API. Go to the API Explorer tag, and copy the token by clicking the copy icon on the right. &lt;/li&gt;
&lt;/ul&gt;

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

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

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

&lt;ul&gt;
&lt;li&gt;Go to the &lt;a href="https://auth0.com/docs/brand-and-customize/text-customization-new-universal-login/prompt-login" rel="noopener noreferrer"&gt;Auth0 “prompt: login” Documentation&lt;/a&gt;, and get the names of the strings you want to change. For example, the key for the following login screen string:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;Log in to ${companyName} to continue to ${clientName}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Is &lt;code&gt;description&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Go to “Set custom text for a specific prompt” in &lt;a href="https://auth0.com/docs/api/management/v2#!/Prompts/put_custom_text_by_language" rel="noopener noreferrer"&gt;Auth0’s API management docs&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;On the top left side of the screen, click “&lt;strong&gt;Set API Token&lt;/strong&gt;”, and paste the API token you copied. &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Select the prompt you would like to make changes to (in our case: login)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Select the language (in our case: EN - English)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Under “body” - add all of the changes you wish to make in this prompt (in our case: description and title) &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; If you want to change more than one prompt, you have to make both changes first, and then save them together. If you do them separately the first will revert to its original state.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Click &lt;strong&gt;TRY&lt;/strong&gt; to save your changes.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;You may want to repeat this process to edit your signup widget as well. To do this, locate the text you want to change here, and repeat the process while choosing signup instead of login &lt;br&gt;
in all the steps.&lt;/p&gt;

&lt;p&gt;&lt;br&gt;
&lt;a&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Things you cannot do with Auth0 universal login
&lt;/h2&gt;

&lt;p&gt;As of the writing of this guide, a feature to change the login widget to request the user to repeat the password on signup is not yet available. A &lt;a href="https://github.com/auth0/lock/issues/61" rel="noopener noreferrer"&gt;GitHub issue for this&lt;/a&gt; has been open since 2014, yet no relevant action was taken.&lt;/p&gt;

&lt;p&gt;*&lt;em&gt;I hope this guide enabled you to set up your own authentication via Auth0. *&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Usually, once you have authentication set up, the next step is to do authorization!&lt;br&gt;
⁠Check out our blog post on the &lt;a href="https://www.permit.io/blog/5-best-practices-for-building-cloud-native-permissions" rel="noopener noreferrer"&gt;5 best practices for building cloud-native permissions&lt;/a&gt;, or visit &lt;a href="//permit.io"&gt;permit.io&lt;/a&gt; to learn more about getting permissions as a service.&lt;/p&gt;

&lt;p&gt;&lt;a&gt;&lt;/a&gt;&lt;br&gt;
You can check out our own template &lt;a href="https://gist.github.com/obsd/9f05d322a03f47d54b302754e9e000df" rel="noopener noreferrer"&gt;on Github&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;---canonical_url:&lt;a href="https://www.permit.io/blog/custom-auth0-universal-login" rel="noopener noreferrer"&gt;https://www.permit.io/blog/custom-auth0-universal-login&lt;/a&gt;&lt;/p&gt;

</description>
      <category>authentication</category>
      <category>login</category>
      <category>tutorial</category>
      <category>auth0</category>
    </item>
  </channel>
</rss>
