<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Kiran Mali on Medium]]></title>
        <description><![CDATA[Stories by Kiran Mali on Medium]]></description>
        <link>https://medium.com/@kdhttps?source=rss-36589f395e1b------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*VwtKiH94ln_vDsV2W6TqXw.jpeg</url>
            <title>Stories by Kiran Mali on Medium</title>
            <link>https://medium.com/@kdhttps?source=rss-36589f395e1b------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Wed, 27 May 2026 17:25:48 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@kdhttps/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com" rel="hub"/>
        <item>
            <title><![CDATA[Using Cedar to Modernize Authz in A Node.js Backend]]></title>
            <link>https://medium.com/janssen-project-feed/using-cedar-to-modernize-authz-in-a-node-js-backend-d204fb4dc55e?source=rss-36589f395e1b------2</link>
            <guid isPermaLink="false">https://medium.com/p/d204fb4dc55e</guid>
            <category><![CDATA[aws]]></category>
            <category><![CDATA[authorization]]></category>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[jwt]]></category>
            <category><![CDATA[nodejs]]></category>
            <dc:creator><![CDATA[Kiran Mali]]></dc:creator>
            <pubDate>Wed, 16 Jul 2025 16:12:36 GMT</pubDate>
            <atom:updated>2025-07-16T16:12:36.341Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*M0jINeApGvVmNsS-" /><figcaption>The Janssen Cedarling — Authz in a Node.js Backend</figcaption></figure><p>This guide demonstrates how to build a Node.js application using a new approach to security: <strong>Token-Based Access Control</strong>, where developers authorize capabilities by presenting a bundle of JWT tokens to a policy engine, specifically the <a href="https://docs.jans.io/head/cedarling/cedarling-overview/"><strong>Janssen Project Cedarling</strong></a>. The Cedar policy syntax is very expressive. A developer can even express policies based on a person’s role or group membership. And that’s exactly what we’re going to do here: <strong>use TBAC to implement RBAC and ABAC</strong>. That may not sound very clear, but please continue for more details on why this makes sense.</p><h3>🎬 Sample Application: Cloud Infrastructure</h3><p>For demo, we’re going to use role-based access control (or “RBAC”) and attribute-based access control (or “ABAC”) to develop a sample application that allows users to create, update, and delete virtual machines. It’s a very simple version of Digital Ocean APIs! In the sample application, we have a simple username and password login that simulates OAuth tokens. In your real application, you can add federated authentication via a standard OpenID Connect Provider. After authentication, Cedarling plays a role in authorization, which will take roles from the ID Token to authorize a user. Below are the roles that will perform the following actions and access virtual machine resources. If a user has enough permission, then allow the action; otherwise, deny.</p><ul><li>Principals: Users with roles like admin, developer, and auditor.</li><li>Actions: Create, Update, Delete, and View virtual machines</li><li>Resources: Virtual Machine</li></ul><p><strong>Roles and Permissions:</strong></p><ol><li>Admin:</li></ol><ul><li>Can perform any operation</li></ul><p>2. Developer:</p><ul><li>Can perform Create But the limit should be &gt; 0</li><li>Can perform Update, View</li><li>Cannot perform Delete</li></ul><p>3. Auditor</p><ul><li>Can perform only View</li></ul><h3>🔧 Setting Up Cedar Policies</h3><p>We’ll use the <a href="https://cloud.gluu.org/agama-lab">Agama-Lab</a> Policy Designer to create and manage our authorization policies. <a href="https://gluu.org/agama/authorization-policy-designer/">Check out the Agama Lab Documents for more information</a>.</p><h4>Step 1: Create Policy Store</h4><ol><li>Sign-in to <a href="https://cloud.gluu.org/agama-lab">Agama Lab</a> with your GitHub ID.</li><li>Open the Policy Designer section.</li><li>Select the repository where you want to save your policies.</li><li>Create a new policy store named JansNodeJSCedarling.</li></ol><h4>Step 2: Define Schema</h4><ol><li>Open the Manage Policy Store section by clicking the arrow link button on the store list.</li><li>Create an Entity called VirtualMachine, which is our sample Resource.</li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*dWjBiyXlUZv731OY0-0hjA.png" /><figcaption>Add Virtual machine entity</figcaption></figure><p>3. Once you add the Resource, you need to associate an action with it. Configure actions (Create, Update, Delete, View):</p><ul><li>Set Principal: User</li><li>Set Resources: VirtualMachine</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*Aq5rEIJ3rRO7vohM" /><figcaption>Add Actions</figcaption></figure><h4>Step 3: Create Policies</h4><ol><li>Go to Manage Policy Store &gt; Policies &gt; Add Policy &gt; Text Editor.</li><li>Copy policies one by one, add to the text editor, and save.</li></ol><p>i. Admin Policies (full access): Admin can perform any action</p><pre>@id(&quot;AdminCanDoAnything&quot;)<br>permit (<br>  principal in Jans::Role::&quot;admin&quot;,<br>  action,<br>  resource<br>);</pre><p>Only the admin can delete resources.</p><pre>@id(&quot;OnlyAdminCanDelete&quot;)<br>forbid (<br>    principal,<br>    action == Jans::Action::&quot;Delete&quot;,<br>    resource<br>)<br>unless {<br>   principal in Jans::Role::&quot;admin&quot;<br>};</pre><p>ii. Developer Policies:</p><p>Developers can create Virtual Machines within limits. Below is an example of attribute-based access control(ABAC) where we are authorizing user access based on id_token.limit.</p><pre>@id(&quot;LimitDeveloperCreateAccess&quot;)<br>permit (<br>  principal in Jans::Role::&quot;developer&quot;,<br>  action in [Jans::Action::&quot;Create&quot;],<br>  resource is Jans::VirtualMachine<br>)<br>when {<br>  principal has id_token.limit &amp;&amp;<br>  principal.id_token.limit &gt; 0<br>};</pre><p>Developers can update and view VMs</p><pre>@id(&quot;DeveloperCanUpdateView&quot;)<br>permit (<br>  principal in Jans::Role::&quot;developer&quot;,<br>  action in [Jans::Action::&quot;Update&quot;,<br>  Jans::Action::&quot;View&quot;],<br>  resource is Jans::VirtualMachine<br>);</pre><p>iii. Auditor Policy</p><p>Auditor can only view resources.</p><pre>@id(&quot;AuditorCanViewOnly&quot;)<br>permit (<br>  principal in Jans::Role::&quot;auditor&quot;,<br>  action == Jans::Action::&quot;View&quot;,<br>  resource<br>);</pre><h4>Step 4: Setup Trusted Issuer</h4><p>A trusted issuer is required to configure the Cedarling. We can configure which token is used for user and workload authentication. access_token is for workload and id_token is for user authentication. The cedarling also validates the access token and ID token, so we need to add configuration for both tokens in the token metadata. <a href="https://docs.jans.io/v1.3.0/cedarling/cedarling-jwt/#summary-of-jwt-validation-mechanisms">More details</a></p><ul><li>Go to Manage Policy Store &gt; Trusted Issuer &gt; Add Issuer.</li><li>Add name, description, and OpenID Configuration endpoint</li><li>Add token metadata</li></ul><pre>{<br>  &quot;access_token&quot;: {<br>    &quot;trusted&quot;: true,<br>    &quot;entity_type_name&quot;: &quot;Jans::Access_token&quot;,<br>    &quot;user_id&quot;: &quot;sub&quot;,<br>    &quot;token_id&quot;: &quot;jti&quot;,<br>    &quot;workload_id&quot;: &quot;rp_id&quot;,<br>    &quot;claim_mapping&quot;: {},<br>    &quot;required_claims&quot;: [<br>      &quot;jti&quot;,<br>      &quot;iss&quot;,<br>      &quot;aud&quot;,<br>      &quot;sub&quot;,<br>      &quot;exp&quot;,<br>      &quot;nbf&quot;<br>    ],<br>    &quot;role_mapping&quot;: &quot;role&quot;,<br>    &quot;principal_mapping&quot;: [<br>      &quot;Jans::Workload&quot;<br>    ]<br>  },<br>  &quot;id_token&quot;: {<br>    &quot;trusted&quot;: true,<br>    &quot;entity_type_name&quot;: &quot;Jans::id_token&quot;,<br>    &quot;user_id&quot;: &quot;sub&quot;,<br>    &quot;token_id&quot;: &quot;jti&quot;,<br>    &quot;role_mapping&quot;: &quot;role&quot;,<br>    &quot;claim_mapping&quot;: {},<br>    &quot;principal_mapping&quot;: [<br>      &quot;Jans::User&quot;<br>    ]<br>  }<br>}</pre><h3>🧑‍💻 Setting up a Node.js Application</h3><h4>Step 1: Install the Cedarling WASM</h4><pre>npm install @janssenproject/cedarling_wasm@0.0.131-nodejs</pre><p>You just need to add the suffix -nodejs in the current version to install Node.js Cedarling version. By default, it installs the web cedarling version.</p><h4>Step 2: Configure the Cedarling</h4><p>Initialize with these properties:</p><pre>export const cedarlingBootstrapProperties = {<br>  CEDARLING_APPLICATION_NAME: &#39;CloudInfrastructure&#39;,<br>  CEDARLING_POLICY_STORE_URI: &#39;&lt;your_policy_store_URI&gt;&#39;,<br>  CEDARLING_USER_AUTHZ: &#39;enabled&#39;,<br>  CEDARLING_LOG_TYPE: &#39;std_out&#39;,<br>  CEDARLING_LOG_LEVEL: &#39;INFO&#39;,<br>  CEDARLING_LOG_TTL: 120,<br>  CEDARLING_PRINCIPAL_BOOLEAN_OPERATION: {<br>    &#39;===&#39;: [{ var: &#39;Jans::User&#39; }, &#39;ALLOW&#39;],<br>  },<br>};</pre><ul><li>CEDARLING_POLICY_STORE_URI: URL of your policy store (from Agama-Lab). In the policy store list, use the link button to copy the policy store URI.</li></ul><h4>Step 3: Create Authorization Client</h4><p>This class implements a singleton pattern for managing Cedar authorization using WebAssembly (WASM), providing a centralized way to initialize the Cedar policy engine and perform authorization checks. It wraps the @janssenproject/cedarling_wasm module to handle policy evaluation through a single, reusable instance that can be accessed throughout the application.</p><pre>class CedarlingClient {<br>  private static instance: CedarlingClient;<br>  private cedarling: Cedarling | null = null;<br>  private initialized = false;<br>  // eslint-disable-next-line @typescript-eslint/no-explicit-any<br><br>  private constructor() {}<br><br>  static getInstance(): CedarlingClient {<br>    if (!CedarlingClient.instance) {<br>      logger.info(&quot;WASM initialing. Creating new instance&quot;);<br>      CedarlingClient.instance = new CedarlingClient();<br>    }<br>    return CedarlingClient.instance;<br>  }<br><br>  // eslint-disable-next-line @typescript-eslint/no-explicit-any<br>  async initialize(policyStoreConfig: any): Promise&lt;void&gt; {<br>    if (!this.initialized) {<br>      this.cedarling = (await init(policyStoreConfig)) as unknown as Cedarling;<br>      logger.info(&quot;WASM initialized&quot;, this.cedarling);<br>      this.initialized = true;<br>    }<br>  }<br><br>  // eslint-disable-next-line @typescript-eslint/no-explicit-any<br>  async authorize(request: any): Promise&lt;AuthorizeResult&gt; {<br>    if (!this.cedarling || !this.initialized) {<br>      const errorMessage = &quot;Cedarling not initialized&quot;;<br>      logger.error(errorMessage);<br>      throw new Error(errorMessage);<br>    }<br>    try {<br>      const result = await this.cedarling.authorize(request);<br>      return result;<br>    } catch (error) {<br>      logger.error(&quot;Error during authorization:&quot;, error);<br>      throw error;<br>    }<br>  }<br>}<br><br>export const cedarlingClient = CedarlingClient.getInstance();</pre><h4>Step 4: Initialize Cedarling</h4><p>We are globally initializing the Cedarling object. You can add it to your app’s startup files. Like in the <a href="https://github.com/GluuFederation/tutorials/tree/master/cedarling/nodejs/nodejs-cedarling">sample</a> application, you can add it in app.ts.</p><pre>app.listen(PORT, () =&gt; {<br>  cedarlingClient.initialize(cedarlingBootstrapProperties).catch(console.error);<br>  logger.info(`Server running on http://localhost:${PORT}`);<br>  swaggerDocs(app, Number(PORT));<br>});</pre><h4>Step 5: Middleware for Authorization</h4><p>This Node.js middleware provides authorization functionality using the Cedarling client, with the ability to enforce authorization checks. The middleware builds the request for cedarling with actions, resources, and tokens, and checks the cedarling authz results. This is just an example to protect the route. You can write your logic to protect resources as per your requirements with the help of the Cedarling client.</p><pre>export const authenticate = async (<br>  req: Request,<br>  res: Response,<br>  next: NextFunction<br>) =&gt; {<br>  try {<br>    const authHeader = req.headers.authorization;<br>    const token = authHeader.split(&#39; &#39;)[1];<br><br>    .<br>    .<br>    .<br><br>    // Cedarling authorization<br>    const request = {<br>      tokens: {<br>        access_token: token,<br>        id_token: token,<br>      },<br>      action: `Jans::Action::&quot;${getAction(req)}&quot;`,<br>      resource: {<br>        type: &quot;Jans::VirtualMachine&quot;,<br>        id: &quot;CloudInfrastructure&quot;,<br>        app_id: &quot;CloudInfrastructure&quot;,<br>        name: &quot;CloudInfrastructure&quot;,<br>        url: {<br>          host: &quot;jans.test&quot;,<br>          path: &quot;/&quot;,<br>          protocol: &quot;http&quot;,<br>        },<br>      },<br>      context: {},<br>    };<br><br>    logger.info(`Request: ${JSON.stringify(request)}`);<br><br>    const result = await cedarlingClient.authorize(request);<br>    logger.info(`Authentication result: ${result.decision}`);<br><br>    if (!result.decision) {<br>      throw new HttpException(403, &quot;Permission denied!&quot;);<br>    }<br><br>    next();<br>  } catch (error) {<br>    logger.error(`Authentication failed: ${error}`);<br>    next(error);<br>  }<br>};<br><br><br>export const getAction = (req: Request): string =&gt; {<br>  if (req.method === &#39;GET&#39;) {<br>    return &#39;View&#39;;<br>  } else if (req.method === &#39;POST&#39;) {<br>    return &#39;Create&#39;;<br>  } else if (req.method === &#39;PUT&#39;) {<br>    return &#39;Update&#39;;<br>  } else if (req.method === &#39;DELETE&#39;) {<br>    return &#39;Delete&#39;;<br>  } else {<br>    return &#39;Invalid&#39;;<br>  }<br>};</pre><p>In the above example:</p><ul><li>We make a middleware authenticate which helps us to make an authorization request to the Cedarling WASM with Access Token and ID Token. Your ID Token should have a Role claim, and if you don&#39;t have a role, then you need to change the policy, which will act like ABAC.</li><li>The getAction function helps to get the correct action.</li><li>There is a request object that checks the authorization for the action. In response, it returns a result where we get which policy is responsible for authorization, timestamp, and decision. Below is an example of the Create(or POST HTTP request) action result. Use result.decision to authorize the request and show/hide elements.</li></ul><pre>{<br>  &quot;id&quot;: &quot;0197a15c-cee0-72da-905f-5800be68fc4b&quot;,<br>  &quot;request_id&quot;: &quot;0197a15c-ced6-7653-b17d-257d50de663e&quot;,<br>  &quot;timestamp&quot;: &quot;2025-06-24T15:25:03.520Z&quot;,<br>  &quot;log_kind&quot;: &quot;Decision&quot;,<br>  &quot;policystore_id&quot;: &quot;22942366f5ad4d8338514bc402d4b901b056051f2bed&quot;,<br>  &quot;policystore_version&quot;: &quot;undefined&quot;,<br>  &quot;principal&quot;: [&quot;User&quot;],<br>  &quot;User&quot;: {},<br>  &quot;diagnostics&quot;: {<br>    &quot;reason&quot;: [<br>      {<br>        &quot;id&quot;: &quot;feac81b973836478ae6478ac63b59d4f2f6691dcddae&quot;,<br>        &quot;description&quot;: &quot;LimitDeveloperCreateAccess&quot;<br>      }<br>    ],<br>    &quot;errors&quot;: []<br>  },<br>  &quot;action&quot;: &quot;Jans::Action::\&quot;Create\&quot;&quot;,<br>  &quot;resource&quot;: &quot;Jans::VirtualMachine::\&quot;CloudInfrastructure\&quot;&quot;,<br>  &quot;decision&quot;: &quot;ALLOW&quot;,<br>  &quot;tokens&quot;: {<br>    &quot;id_token&quot;: {<br>      &quot;jti&quot;: &quot;6dV4hO0kQ3OaPJerJHNwgg&quot;<br>    },<br>    &quot;access_token&quot;: {<br>      &quot;jti&quot;: &quot;6dV4hO0kQ3OaPJerJHNwgg&quot;<br>    }<br>  },<br>  &quot;decision_time_micro_sec&quot;: 7000,<br>  &quot;pdp_id&quot;: &quot;a446ecda-b6aa-4ad5-9d0e-b7c09b1fb30e&quot;,<br>  &quot;application_id&quot;: &quot;CloudInfrastructure&quot;<br>}</pre><h3>✅ Test Cases</h3><h4>Admin Authorization</h4><p>Let’s log in as an admin user and check the authorization. According to the above authorization policies, admin can access any resource. As you can see in the video below, Sachin is an admin user, and he has the admin role.</p><p>🟢 Admin can Create a VM</p><p>🟢 Admin can Update a VM</p><p>🟢 Admin can Delete a VM</p><p>🟢 Admin can View a VM</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2FXnU072a64Yk%3Ffeature%3Doembed&amp;display_name=YouTube&amp;url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DXnU072a64Yk&amp;image=https%3A%2F%2Fi.ytimg.com%2Fvi%2FXnU072a64Yk%2Fhqdefault.jpg&amp;type=text%2Fhtml&amp;schema=youtube" width="640" height="480" frameborder="0" scrolling="no"><a href="https://medium.com/media/924f6d9b0f7196ef037104ec35c0bb1b/href">https://medium.com/media/924f6d9b0f7196ef037104ec35c0bb1b/href</a></iframe><h4>Developer Authorization</h4><p>Log in with a developer role user and check the authorization.</p><p>🟢 Developer with limit, can Create a VM. You can see the video below. Dhoni is a developer user, and he has a limit limit: 1.</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2FHwzjxS1FYW4%3Ffeature%3Doembed&amp;display_name=YouTube&amp;url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DHwzjxS1FYW4&amp;image=https%3A%2F%2Fi.ytimg.com%2Fvi%2FHwzjxS1FYW4%2Fhqdefault.jpg&amp;type=text%2Fhtml&amp;schema=youtube" width="640" height="480" frameborder="0" scrolling="no"><a href="https://medium.com/media/20951b27b797757edbc1de83932cc3fe/href">https://medium.com/media/20951b27b797757edbc1de83932cc3fe/href</a></iframe><p>🔴 A developer with no limit cannot Create a VM. You can see the video below. Virat is a developer user with limit: 0 means he cannot create a new virtual machine.</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2FbwkxQxyS3Hs%3Ffeature%3Doembed&amp;display_name=YouTube&amp;url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DbwkxQxyS3Hs&amp;image=https%3A%2F%2Fi.ytimg.com%2Fvi%2FbwkxQxyS3Hs%2Fhqdefault.jpg&amp;type=text%2Fhtml&amp;schema=youtube" width="640" height="480" frameborder="0" scrolling="no"><a href="https://medium.com/media/d6f51bec39b8befd94bd3e4f019736c5/href">https://medium.com/media/d6f51bec39b8befd94bd3e4f019736c5/href</a></iframe><p>🟢 Developer can Update a VM</p><p>🔴 Developer cannot Delete a VM</p><p>🟢 Developer can View a VM</p><h4>Auditor Authorization</h4><p>An auditor user can only view virtual machine resources.</p><p>🟢 Auditor can only View a VM</p><p>🔴 Auditor cannot Create a VM</p><p>🔴 Auditor cannot Update a VM</p><p>🔴 Auditor cannot Delete a VM</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2FX2-PkPG8tpc%3Ffeature%3Doembed&amp;display_name=YouTube&amp;url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DX2-PkPG8tpc&amp;image=https%3A%2F%2Fi.ytimg.com%2Fvi%2FX2-PkPG8tpc%2Fhqdefault.jpg&amp;type=text%2Fhtml&amp;schema=youtube" width="640" height="480" frameborder="0" scrolling="no"><a href="https://medium.com/media/ede3bb9345eaf34df8f8811d54e20c9c/href">https://medium.com/media/ede3bb9345eaf34df8f8811d54e20c9c/href</a></iframe><h3>📚 Resources</h3><p>For a complete implementation, reference the:</p><ul><li><a href="https://github.com/GluuFederation/tutorials/tree/nodejs-blog/cedarling/nodejs/nodejs-cedarling">Node.js Demo project</a></li><li><a href="https://raw.githubusercontent.com/kdhttps/pd-first/refs/heads/agama-lab-policy-designer/22942366f5ad4d8338514bc402d4b901b056051f2bed.json">Policy Store</a></li><li>The <a href="https://docs.jans.io/head/cedarling">Janssen Cedarling Documentation</a></li><li><a href="https://jans.io">Janssen Home Page</a></li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=d204fb4dc55e" width="1" height="1" alt=""><hr><p><a href="https://medium.com/janssen-project-feed/using-cedar-to-modernize-authz-in-a-node-js-backend-d204fb4dc55e">Using Cedar to Modernize Authz in A Node.js Backend</a> was originally published in <a href="https://medium.com/janssen-project-feed">Janssen Project Feed</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Using Cedar to Modernize Authz in a React Frontend]]></title>
            <link>https://medium.com/janssen-project-feed/using-cedar-to-modernize-authz-in-a-react-frontend-f30c637d879c?source=rss-36589f395e1b------2</link>
            <guid isPermaLink="false">https://medium.com/p/f30c637d879c</guid>
            <category><![CDATA[single-page-applications]]></category>
            <category><![CDATA[typescript]]></category>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[react]]></category>
            <category><![CDATA[front-end-development]]></category>
            <dc:creator><![CDATA[Kiran Mali]]></dc:creator>
            <pubDate>Mon, 23 Jun 2025 17:47:20 GMT</pubDate>
            <atom:updated>2026-04-04T08:31:01.537Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*Ojn7H9DUY_6MBEVZ.jpeg" /></figure><p>Security-aware frontends enable developers to personalize and improve user experiences. While in the past this meant a lot of “if-then” statements, or complex mappings of user roles to capabilities, the recent invention of the <a href="https://www.cedarpolicy.com/">Cedar</a> policy syntax offers new opportunities for React developers to leverage an embedded policy engine in their applications.</p><p>There are some other good reasons to use Cedar. Moving to “declarative” policies makes it easier for the CISO or security team to review application security rules. Also, the use of a Cedar policy engine guarantees consistent logs for all security decisions in an application. And consistent logging is the key to modern threat detection.</p><p>There has been another important security innovation that impacts React frontend developers: the move to JWT tokens to provide evidence for federated login. Today, instead of simply the user’s roles — just one vector of many — developers can make policies on any of the claims in the tokens they receive during the authentication and authorization journey. The use of tokens to govern access to resources is generically known as <strong>Token-Based Access Control.</strong></p><p>This how-to article will introduce the <a href="https://docs.jans.io/head/cedarling/cedarling-overview/"><strong>Janssen Project Cedarling</strong></a>. This NPM package uses the performant Cedar Rust engine to enable React Developers to run their own local, embedded policy decision point (“PDP”). We’ll walk through setting up the integration with a practical example involving multiple roles and conditional policies. You’ll learn how to:</p><ul><li>Define the authorization schema</li><li>Configure access policies</li><li>Evaluate authorization requests</li><li>Implement Cedarling’s streamlined authorization in React with minimal code</li></ul><h3>Sample Application: Task Management</h3><p>For demo, we’re going to use <strong>role-based access</strong> <strong>control</strong> (or <strong>“RBAC”</strong>) to develop a sample application that performs Task Management. It’s a very simple version of Trello! For example, we will also support federated authentication via a standard OpenID Connect Provider. After authentication, <strong>Cedarling plays a role in authorization</strong>, which will take <strong>roles from the ID Token to authorize a user</strong>. Below are the roles which perform will perform the following actions and access Task resources. If a user has sufficient permission, allow the action; otherwise, deny it.</p><p>For our demonstration, we’ll implement <strong>Role-Based Access Control (RBAC)</strong> to build a sample Task Management application — essentially a simplified version of Trello. The application will feature:</p><ol><li>Federated Authentication: Users will authenticate through a standard OpenID Connect Provider</li><li>Cedarling Authorization: After authentication, Cedarling will handle authorization by:</li></ol><ul><li>Extracting user roles from the ID Token</li><li>Evaluating permissions against Task resources</li><li>Allowing or denying actions based on the user’s role</li></ul><p>The system will enforce these access controls when users attempt to perform actions, only permitting operations when they have sufficient permissions.</p><ul><li><strong>Principals</strong>: Users with roles like Admin, Manager, and Member.</li><li><strong>Actions</strong>: Add, Update, Delete, and View</li><li><strong>Resources</strong>: Task</li></ul><p>Roles and Permissions:</p><ol><li><strong>Admin</strong></li></ol><ul><li>Can perform any operation</li></ul><p>2. <strong>Manager</strong></p><ul><li>Can perform Add, Update, View</li><li>Cannot perform Delete</li></ul><p>3. <strong>Member</strong></p><ul><li>Can perform only View</li></ul><h3>Prerequisite</h3><ol><li>OpenID Connect Server: Use any compliant provider like <a href="https://docs.jans.io/">Janssen</a>, Google, or Okta.</li><li>React Application: Use any framework like Next.js or Vite.js to create a Fresh React App.</li></ol><h3>Setting Up Policies</h3><p>We’ll use the <a href="https://cloud.gluu.org/agama-lab"><strong>Agama-Lab</strong></a> Policy Designer to create and manage our authorization policies. For more information, see the <a href="https://gluu.org/agama/authorization-policy-designer/"><strong>Agama Lab Documentation</strong></a>.</p><h3>Step 1: Create Policy Store</h3><ol><li>Sign in to <a href="https://cloud.gluu.org/agama-lab">Agama Lab</a> with your GitHub ID.</li><li>Open the Policy Designer section.</li><li>Select the repository where you want to save your policies.</li><li>Create a new policy store named JanssenReactCedarlingRBAC.</li></ol><h3>Step 2: Define Schema</h3><ol><li>Open the Manage Policy Store section by clicking the arrow link button on the store list.</li><li>Create an Entity called Task, which is our sample Resource.</li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*ek3bMu-3qbjBTtS_" /><figcaption>Create a Task Entity</figcaption></figure><p>3. Once you add the Resource, you must associate an action with it. Configure actions (Add, Update, Delete, View):</p><ul><li>Set Principal: User</li><li>Set Resources: Task</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*nxhNOccNnCFOlQBB" /><figcaption>Add new Cedar action</figcaption></figure><h3>Step 3: Create Policies</h3><ol><li>Go to Manage Policy Store &gt; Policies &gt; Add Policy &gt; Text Editor.</li><li>Copy policies one by one, add to the text editor, and save.</li></ol><ul><li><strong>Admin Policy</strong> (full access):</li></ul><pre>@id(&quot;AdminPerformAnyOperationOnResource&quot;)<br>permit(<br>  principal in Jans::Role::&quot;admin&quot;,<br>  action,<br>  resource<br>);</pre><ul><li><strong>Manager Policy</strong> (restricted access):</li></ul><pre>@id(&quot;ManagerCanAddUpdateViewTask&quot;)<br>permit (<br>  principal in Jans::Role::&quot;manager&quot;,<br>  action in [Jans::Action::&quot;Add&quot;,<br>  Jans::Action::&quot;Update&quot;,<br>  Jans::Action::&quot;View&quot;],<br>  resource is Jans::Task<br>);</pre><ul><li><strong>Member Policy</strong> (view only):</li></ul><pre>@id(&quot;MemberCanOnlyViewTask&quot;)<br>permit (<br>  principal in Jans::Role::&quot;member&quot;,<br>  action in [Jans::Action::&quot;View&quot;],<br>  resource is Jans::Task<br>);</pre><h3>Step 4: Set up Trusted Issuer</h3><p>A trusted issuer is required to configure the Cedarling. We can configure which token is used for user and workload authentication. access_token is for workload and id_token is for user authentication. The cedarling also validates the access token and ID token, so we need to add configuration for both tokens in the token metadata. <a href="https://docs.jans.io/v1.3.0/cedarling/cedarling-jwt/#summary-of-jwt-validation-mechanisms">More details</a></p><ul><li>Go to Manage Policy Store &gt; Trusted Issuer &gt; Add Issuer.</li><li>Add name, description, and OpenID Configuration endpoint</li><li>Add token metadata</li></ul><pre>{<br>  &quot;access_token&quot;: {<br>    &quot;trusted&quot;: true,<br>    &quot;entity_type_name&quot;: &quot;Jans::Access_token&quot;,<br>    &quot;user_id&quot;: &quot;sub&quot;,<br>    &quot;token_id&quot;: &quot;jti&quot;,<br>    &quot;workload_id&quot;: &quot;rp_id&quot;,<br>    &quot;claim_mapping&quot;: {},<br>    &quot;required_claims&quot;: [],<br>    &quot;role_mapping&quot;: &quot;role&quot;,<br>    &quot;principal_mapping&quot;: [<br>      &quot;Jans::Workload&quot;<br>    ]<br>  },<br>  &quot;id_token&quot;: {<br>    &quot;trusted&quot;: true,<br>    &quot;entity_type_name&quot;: &quot;Jans::id_token&quot;,<br>    &quot;user_id&quot;: &quot;sub&quot;,<br>    &quot;token_id&quot;: &quot;jti&quot;,<br>    &quot;role_mapping&quot;: &quot;role&quot;,<br>    &quot;claim_mapping&quot;: {},<br>    &quot;principal_mapping&quot;: [<br>      &quot;Jans::User&quot;<br>    ]<br>  }<br>}</pre><h3>Step 5: Generate <strong>CJAR</strong></h3><p>The Cedarling accepts a .<strong>CJAR</strong> zip file containing all the policies, schemas, and trusted issuers. To generate CJAR, go to Policy Manage Page &gt; Release &gt; Pre-release.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*lVRxV69mRRt21nlbaKun6Q.png" /></figure><p>Once you release, you can find releases with the CJAR file on your GitHub.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*o036zZoGDWqt_X6BddKqlQ.png" /></figure><h3>Setting up a React Application</h3><h3>Step 1: Install the Cedarling WASM</h3><pre>npm install @janssenproject/cedarling_wasm@0.0.338</pre><p>For Vite.js, update vite.config.ts:</p><pre>import { defineConfig } from &quot;vite&quot;;<br><br>export default defineConfig({<br>  optimizeDeps: {<br>    exclude: [&quot;@janssenproject/cedarling_wasm&quot;],<br>  },<br>});</pre><h3>Step 2: Configure the Cedarling</h3><p>Initialize with these properties:</p><pre>export const cedarlingBootstrapProperties = {<br>  CEDARLING_POLICY_STORE_URI: &quot;&lt;your-cjar-file-link&gt;&quot;,<br>  CEDARLING_APPLICATION_NAME: &quot;TaskManager&quot;,<br>  CEDARLING_USER_AUTHZ: &quot;enabled&quot;,<br>  CEDARLING_WORKLOAD_AUTHZ: &quot;disabled&quot;,<br>  CEDARLING_LOG_TYPE: &quot;std_out&quot;,<br>  CEDARLING_LOG_LEVEL: &quot;INFO&quot;,<br>  CEDARLING_PRINCIPAL_BOOLEAN_OPERATION: {<br>    &quot;===&quot;: [{ var: &quot;Jans::User&quot; }, &quot;ALLOW&quot;],<br>  },<br>};</pre><ul><li>CEDARLING_POLICY_STORE_URI: URL of your CJAR file link.</li></ul><p>In this demo, we are not using a CEDARLING_POLICY_STORE_URI property in the configuration because the GitHub CJAR file download link returns a cross-origin problem for the React App. In a React App, we have server-side routes to fetch the CJAR file from GitHub.</p><p><a href="https://docs.jans.io/stable/cedarling/tutorials/javascript/#policy-store-sources-wasm">Check out Cedarling Documents</a> for more ways to fetch and initialize Cedarling with CJAR.</p><h3>Step 3: Create Authorization Client</h3><p>This class implements a singleton pattern for managing Cedar authorization using WebAssembly (WASM), providing a centralized way to initialize the Cedar policy engine and perform authorization checks. It wraps the @janssenproject/cedarling_wasm module to handle policy evaluation through a single, reusable instance that can be accessed throughout the application.</p><pre>class CedarlingClient {<br>  private static instance: CedarlingClient;<br>  private cedarling: Cedarling | null = null;<br>  private initialized = false;<br>  private wasmModule: any = null;<br><br>  private constructor() {}<br><br>  static getInstance(): CedarlingClient {<br>    if (!CedarlingClient.instance) {<br>      CedarlingClient.instance = new CedarlingClient();<br>    }<br>    return CedarlingClient.instance;<br>  }<br><br>  async initialize(policyStoreConfig: any): Promise&lt;void&gt; {<br>    if (!this.initialized) {<br>      this.wasmModule = await initWasm();<br>      // Fetch CJAR zip file<br>      const responseArrayBuffer = await fetchPolicyStoreZip();<br><br>      // Initialize Cedarling using init_from_archive_bytes<br>      const bytes = new Uint8Array(responseArrayBuffer);<br>      this.cedarling = (await init_from_archive_bytes(<br>        policyStoreConfig,<br>        bytes,<br>      )) as unknown as Cedarling;<br>      console.log(&quot;WASM initialized&quot;, this.cedarling);<br><br>      this.initialized = true;<br>    }<br>  }<br><br>  async authorize(request: any): Promise&lt;AuthorizeResult&gt; {<br>    if (!this.cedarling || !this.initialized) {<br>      throw new Error(&quot;Cedarling not initialized&quot;);<br>    }<br>    try {<br>      const result = await this.cedarling.authorize(request);<br>      return result;<br>    } catch (error) {<br>      console.error(&quot;Error during authorization:&quot;, error);<br>      throw error;<br>    }<br>  }<br>}<br><br>export const cedarlingClient = CedarlingClient.getInstance();</pre><h3>Step 4: Initialize Cedarling</h3><p>We are globally initializing the Cedarling object. You can add it to your app’s startup files. Like in the ViteJS case, you can add it in App.tsx, and in the Next JS case, you can add it in src/layout.tsx.</p><pre>useEffect(() =&gt; {<br>  cedarlingClient.initialize(cedarlingBootstrapProperties).catch(console.error);<br>}, []);</pre><h3>Step 5: React Hook for Authorization</h3><p>This Reack hook provides authorization functionality using the Cedarling client, with the ability to enforce authorization checks when enabled through environment variables. The hook manages loading and error states while processing authorization requests, and returns a boolean or AuthorizeResult indicating whether the authorization was successful.</p><pre>import { useCallback, useState } from &quot;react&quot;;<br>import { cedarlingClient } from &quot;./cedarlingUtils&quot;;<br>import { parseJwt } from &quot;./parseJWT&quot;;<br>import { AuthorizeResult } from &quot;@janssenproject/cedarling_wasm&quot;;<br><br>export function useCedarling() {<br>  const [isLoading, setIsLoading] = useState(false);<br>  const [error, setError] = useState&lt;Error | null&gt;(null);<br>  const authorize = useCallback(<br>    async (request: any): Promise&lt;AuthorizeResult&gt; =&gt; {<br>      setIsLoading(true);<br>      setError(null);<br>      try {<br>        // debug logs<br>        console.log(&quot;Enforcing Cedarling authorization&quot;);<br>        console.log(&quot;Request: &quot;, request);<br>        console.log(&quot;Decoded idToken: &quot;, parseJwt(request.tokens.id_token as string));<br>        console.log(&quot;Decoded accessToken: &quot;,parseJwt(request.tokens.access_token as string));<br>        // userinfo token case<br>        // console.log(&#39;Decoded userInfo: &#39;, parseJwt(request.tokens.userinfo_token as string))<br>        return await cedarlingClient.authorize(request);<br>      } catch (err) {<br>        const error = err instanceof Error ? err : new Error(&quot;Authorization failed&quot;);<br>        setError(error);<br>        throw error;<br>      } finally {<br>        setIsLoading(false);<br>      }<br>    },<br>    []<br>  );<br>  return { authorize, isLoading, error };<br>}</pre><h3>Step 6: Protect Actions and Components</h3><p>Use React Hooks to protect actions and components. Your ID Token should have a role claim. It can be one value, like role: admin or an array, like role: [&quot;admin&quot;, &quot;manager&quot;]both are valid. Check the <a href="https://docs.jans.io/head/cedarling/cedarling-entities/">Cedarling entities document</a> for more details about role entity creation and usage.</p><p>Below is an example of the Task React Page:</p><pre>import { useCedarling } from &quot;@/factories/useCedarling&quot;;<br>import { AuthorizeResult } from &quot;@janssenproject/cedarling_wasm&quot;;<br><br>export default function TasksPage() {<br>  const { authorize } = useCedarling();<br><br>  const cedarlingRequest = async (action: string) =&gt; {<br>    const idToken = &quot;&lt;your_id_token&gt;&quot;;<br>    const accessToken = &quot;&lt;your_access_token&gt;&quot;;<br><br>    const request = {<br>      tokens: {<br>        access_token: accessToken,<br>        id_token: idToken,<br>      },<br>      action: `Jans::Action::&quot;${action}&quot;`,<br>      resource: {<br>        type: &quot;Jans::Task&quot;,<br>        id: &quot;App&quot;,<br>        app_id: &quot;App&quot;,<br>        name: &quot;App&quot;,<br>        url: {<br>          host: &quot;jans.test&quot;,<br>          path: &quot;/&quot;,<br>          protocol: &quot;http&quot;,<br>        },<br>      },<br>      context: {},<br>    };<br><br>    const result: AuthorizeResult = await authorize(request);<br>    return result;<br>  };<br><br>  const handleAdd = async () =&gt; {<br>    try {<br>      const result = await cedarlingRequest(&quot;Add&quot;);<br>      console.log(result);<br>      if (result.decision) {<br>        alert(&quot;Successfully added!&quot;);<br>      } else {<br>        alert(&quot;You are not allowed to add new Task!&quot;);<br>      }<br>    } catch (e) {<br>      alert(&quot;You are not allowed to add new Task!&quot;);<br>      console.log(e);<br>    }<br>  };<br>}<br><br>&lt;button className=&quot;btn btn-primary mb-3&quot; onClick={handleAdd}&gt;<br>  &lt;FaPlus className=&quot;me-2&quot; /&gt;<br>  Add Task<br>&lt;/button&gt;;</pre><p>In the above example, there are 2 things:</p><ul><li>First, we make a function cedarlingRequest which accepts an action and helps us to make an authorization request to the Cedarling WASM with Access Token and ID Token. Your ID Token should have a Role claim, and if you don&#39;t have a role, then you need to change the policy, which will act like ABAC.</li><li>Second, we have the handleAdd function, which helps us to request and check the authorization for the Add operation. In response, it returns a result where we get which policy is responsible for authorization, the timestamp, and the decision. Below is an example of the result. Use result.decision to authorize the request and show/hide elements.</li></ul><pre>{<br>  &quot;id&quot;: &quot;0196118a-ce6e-74c8-9c25-5da154aa8b90&quot;,<br>  &quot;request_id&quot;: &quot;0196118a-ce6a-7653-b64c-e5fb9722c1d1&quot;,<br>  &quot;timestamp&quot;: &quot;2025-04-08T00:07:11.662Z&quot;,<br>  &quot;log_kind&quot;: &quot;Decision&quot;,<br>  &quot;policystore_id&quot;: &quot;87d2c8877a2455a16149c55d956565e1d18ac81ba10a&quot;,<br>  &quot;policystore_version&quot;: &quot;undefined&quot;,<br>  &quot;principal&quot;: [&quot;User&quot;],<br>  &quot;User&quot;: {},<br>  &quot;diagnostics&quot;: {<br>    &quot;reason&quot;: [<br>      {<br>        &quot;id&quot;: &quot;6b51f8244fe1fc3b273733f9d93def7f07080367fbc1&quot;,<br>        &quot;description&quot;: &quot;ManagerCanAddUpdateViewTask&quot;<br>      }<br>    ],<br>    &quot;errors&quot;: []<br>  },<br>  &quot;action&quot;: &quot;Jans::Action::\&quot;Add\&quot;&quot;,<br>  &quot;resource&quot;: &quot;Jans::Task::\&quot;App\&quot;&quot;,<br>  &quot;decision&quot;: &quot;ALLOW&quot;,<br>  &quot;tokens&quot;: {<br>    &quot;id_token&quot;: {<br>      &quot;jti&quot;: &quot;J4TB2NsgTZOBtPTYTzHtmg&quot;<br>    },<br>    &quot;access_token&quot;: {<br>      &quot;jti&quot;: &quot;hNhnQW18RA2AIOh5ihOfTQ&quot;<br>    }<br>  },<br>  &quot;decision_time_micro_sec&quot;: 3000,<br>  &quot;pdp_id&quot;: &quot;bbcf165b-1b7b-452a-af46-b9dbf3ae7cf0&quot;,<br>  &quot;application_id&quot;: &quot;AgamaLab&quot;<br>}</pre><p>Like we handled the Add action, you can handle other actions and show hide components.</p><h3>Step 7: Protecting UI Components</h3><p>This ProtectedSection component is a React wrapper that controls access to UI components based on user authorization. It takes a resource ID and optional action ID, checks if the user has permission to access that resource using Cedar authorization, and either displays the protected content (children) if authorized or shows a fallback component (typically an error message) if access is denied.</p><pre>import { useCedarling } from &quot;@/factories/useCedarling&quot;;<br>import React from &quot;react&quot;;<br><br>export function ProtectedSection({<br>  accessToken,<br>  idToken,<br>  actionId,<br>  resourceId,<br>  children,<br>  fallback = (<br>    &lt;div&gt;<br>      &lt;div&gt;Access Denied&lt;/div&gt;<br>      {`Please contact your administrator.`}<br>    &lt;/div&gt;<br>  ),<br>  loadingFallback = &lt;div&gt;Loading...&lt;/div&gt;,<br>}: ProtectedSectionProps) {<br>  const { authorize, isLoading, error } = useCedarling();<br>  const [isAuthorized, setIsAuthorized] = React.useState(false);<br><br>  React.useEffect(() =&gt; {<br>    const checkAuthorization = async () =&gt; {<br>      const request = {<br>        tokens: {<br>          access_token: accessToken,<br>          id_token: idToken,<br>        },<br>        action: `Jans::Action::&quot;${actionId}&quot;`,<br>        resource: { type: &quot;Jans::Task&quot;, id: resourceId, name: resourceId },<br>        context: {},<br>      };<br>      try {<br>        const result = await authorize(request);<br>        setIsAuthorized(result.decision);<br>      } catch (err: any) {<br>        setIsAuthorized(false);<br>      }<br>    };<br>    checkAuthorization();<br>  }, [accessToken, idToken, authorize, actionId, resourceId]);<br><br>  if (isLoading) return &lt;&gt;{loadingFallback}&lt;/&gt;;<br>  if (error) return &lt;div&gt;Error: {error?.message}&lt;/div&gt;;<br>  if (!isAuthorized) return &lt;&gt;{fallback}&lt;/&gt;;<br>  return &lt;&gt;{children}&lt;/&gt;;<br>}</pre><p>Use ProtectedSection to protect any elements. Your ID Token should have a role claim. It can be one value, like role: admin or an array like role: [&quot;admin&quot;, &quot;manager&quot;, &quot;member&quot;]both are valid. Check the <a href="https://docs.jans.io/head/cedarling/cedarling-entities/">Cedarling entities document</a> for more details about role entity creation and usage.</p><pre>&lt;ProtectedSection<br>  accessToken={accessToken}<br>  idToken={idToken}<br>  resourceId=&quot;App&quot;<br>  actionId=&quot;Delete&quot;<br>&gt;<br>  &lt;h1&gt;Welcome, permission granted!&lt;/h1&gt;<br>&lt;/ProtectedSection&gt;</pre><h3>Test Cases</h3><h3>Admin Authorization</h3><p>Let’s log in as an <strong>admin</strong> user and check the authorization. As per the above authorization policies, admins can access any resource. As you can see in the video below, Sachin is an admin user, and he has the admin role in ID Token.</p><p>🟢 Admin can Add a task</p><p>🟢 Admin can Update a task</p><p>🟢 Admin can Delete a task</p><p>🟢 Admin can view a task</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2FaxDsoPvuiV0%3Ffeature%3Doembed&amp;display_name=YouTube&amp;url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DaxDsoPvuiV0&amp;image=https%3A%2F%2Fi.ytimg.com%2Fvi%2FaxDsoPvuiV0%2Fhqdefault.jpg&amp;type=text%2Fhtml&amp;schema=youtube" width="640" height="480" frameborder="0" scrolling="no"><a href="https://medium.com/media/a90b652869f7e1771201b9df7aef8391/href">https://medium.com/media/a90b652869f7e1771201b9df7aef8391/href</a></iframe><h3>Manager Authorization</h3><p>Log in with a <strong>manager</strong> role user and check the authorization. As per our authorization policies, a manager cannot perform the `Delete` action.</p><p>🟢 Manager can Add a task</p><p>🟢 Manager can Update a task</p><p>🟢 Manager can view a task</p><p>🔴 Manager cannot Delete a task</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2FRgTaI-z6VMY%3Ffeature%3Doembed&amp;display_name=YouTube&amp;url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DRgTaI-z6VMY&amp;image=https%3A%2F%2Fi.ytimg.com%2Fvi%2FRgTaI-z6VMY%2Fhqdefault.jpg&amp;type=text%2Fhtml&amp;schema=youtube" width="640" height="480" frameborder="0" scrolling="no"><a href="https://medium.com/media/cda6e750785ac81c785167ba98f8860b/href">https://medium.com/media/cda6e750785ac81c785167ba98f8860b/href</a></iframe><h3>Member Authorization</h3><p>Log in with a <strong>member</strong> role user and check the authorization. As per our authorization policies, members can only `view` tasks.</p><p>🟢 Member can view a task</p><p>🔴 Member cannot Add a task</p><p>🔴 Member cannot Update a task</p><p>🔴 Member cannot view a task</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2FO4sgR1xZSqg%3Ffeature%3Doembed&amp;display_name=YouTube&amp;url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DO4sgR1xZSqg&amp;image=https%3A%2F%2Fi.ytimg.com%2Fvi%2FO4sgR1xZSqg%2Fhqdefault.jpg&amp;type=text%2Fhtml&amp;schema=youtube" width="640" height="480" frameborder="0" scrolling="no"><a href="https://medium.com/media/c2f855227a88c0ef6670c2f4413d1fa7/href">https://medium.com/media/c2f855227a88c0ef6670c2f4413d1fa7/href</a></iframe><h3>Key Takeaways</h3><ul><li>The Cedarling is easy to integrate natively in a React Application and offers policy expression, from simple RBAC policies to complex contextual policies.</li><li>The Cedarling makes it easy to protect components and limit user access. Use ProtectedSection to restrict UI elements.</li><li>Policy authoring is centralized via the <a href="https://cloud.gluu.org/agama-lab">Agama Lab developer portal</a>.</li></ul><p>For a complete implementation, reference the:</p><ul><li><a href="https://github.com/GluuFederation/tutorials/tree/master/cedarling/react/next-js-cedarling">Next JS Demo project</a></li><li><a href="https://github.com/kdhttps/new-pd/releases/tag/v0.0.7">Policy Store</a></li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=f30c637d879c" width="1" height="1" alt=""><hr><p><a href="https://medium.com/janssen-project-feed/using-cedar-to-modernize-authz-in-a-react-frontend-f30c637d879c">Using Cedar to Modernize Authz in a React Frontend</a> was originally published in <a href="https://medium.com/janssen-project-feed">Janssen Project Feed</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[From RBAC to TBAC: Modernizing Authz in React Browser Apps]]></title>
            <link>https://medium.com/@kdhttps/from-rbac-to-tbac-modernizing-authz-in-react-browser-apps-1d449f6b4840?source=rss-36589f395e1b------2</link>
            <guid isPermaLink="false">https://medium.com/p/1d449f6b4840</guid>
            <dc:creator><![CDATA[Kiran Mali]]></dc:creator>
            <pubDate>Wed, 30 Apr 2025 08:44:04 GMT</pubDate>
            <atom:updated>2025-04-30T08:44:04.715Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*bm5kc_zqjvx0dHpqNARUWQ.jpeg" /><figcaption>Authorize React Application with the Janssen Cedarling</figcaption></figure><p>This guide demonstrates how to build a React application using a new approach to security: <strong>Token-Based Access Control</strong>, where developers authorize capabilities by presenting a bundle of JWT tokens to a policy engine, in this case, the<strong> </strong><a href="https://docs.jans.io/head/cedarling/cedarling-overview/"><strong>Janssen Project Cedarling</strong></a>. The <strong>Cedar</strong> policy syntax is very expressive. A developer can express policies based on a person’s role or group membership. And that’s just what we will do here… use <strong>TBAC</strong> to implement <strong>RBAC</strong>. That may sound confusing, but carry on further for more details on why this makes sense!</p><p>We’ll walk through setting up the integration with a practical example involving multiple roles and conditional policies. You’ll learn how to:</p><ul><li>Define the authorization schema</li><li>Configure access policies</li><li>Evaluate authorization requests</li><li>Implement Cedarling’s streamlined authorization in React with minimal code</li></ul><h3>Sample Application: Task Management</h3><p>For demo, we’re going to use <strong>role-based access</strong> control (or <strong>“RBAC”</strong>) to develop a sample application that performs Task Management. It’s a very simple version of Trello! For example, we will also support federated authentication via a standard OpenID Connect Provider. After authentication, <strong>Cedarling plays a role in authorization</strong>, which will take <strong>roles from the ID Token to authorize a user</strong>. Below are the roles which perform will perform the following actions and access Task resources. If a user has enough permission, then allow the action; otherwise, deny.</p><p>For our demonstration, we’ll implement <strong>Role-Based Access Control (RBAC)</strong> to build a sample Task Management application — essentially a simplified version of Trello. The application will feature:</p><ol><li>Federated Authentication: Users will authenticate through a standard OpenID Connect Provider</li><li>Cedarling Authorization: After authentication, Cedarling will handle authorization by:</li></ol><ul><li>Extracting user roles from the ID Token</li><li>Evaluating permissions against Task resources</li><li>Allowing or denying actions based on the user’s role</li></ul><p>The system will enforce these access controls when users attempt to perform actions, only permitting operations when they have sufficient permissions.</p><ul><li><strong>Principals</strong>: Users with roles like Admin, Manager, and Member.</li><li><strong>Actions</strong>: Add, Update, Delete, and View</li><li><strong>Resources</strong>: Task</li></ul><p>Roles and Permissions:</p><ol><li><strong>Admin</strong></li></ol><ul><li>Can perform any operation</li></ul><p>2. <strong>Manager</strong></p><ul><li>Can perform Add, Update, View</li><li>Cannot perform Delete</li></ul><p>3. <strong>Member</strong></p><ul><li>Can perform only View</li></ul><h3>Prerequisite</h3><ol><li>OpenID Connect Server: Use any compliant provider like <a href="https://docs.jans.io/">Janssen</a>, Google, or Okta.</li><li>React Application: Use any framework like Next.js or Vite.js to create a Fresh React App.</li></ol><h3>Setting Up Policies</h3><p>We’ll use the <a href="https://cloud.gluu.org/agama-lab"><strong>Agama-Lab</strong></a> Policy Designer to create and manage our authorization policies. For more information, see the <a href="https://gluu.org/agama/authorization-policy-designer/"><strong>Agama Lab Documentation</strong></a>.</p><h3>Step 1: Create Policy Store</h3><ol><li>Sign in to <a href="https://cloud.gluu.org/agama-lab">Agama Lab</a> with your GitHub ID.</li><li>Open the Policy Designer section.</li><li>Select the repository where you want to save your policies.</li><li>Create a new policy store named JanssenReactCedarlingRBAC.</li></ol><h3>Step 2: Define Schema</h3><ol><li>Open the Manage Policy Store section by clicking the arrow link button on the store list.</li><li>Create an Entity called Task, which is our sample Resource.</li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*UcO2N5VRO4qQgygB" /><figcaption>Create a Task Entity</figcaption></figure><p>3. Once you add the Resource, you must associate an action with it. Configure actions (Add, Update, Delete, View):</p><ul><li>Set Principal: User</li><li>Set Resources: Task</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*_VTXtsa25cgFWqZS" /><figcaption>Add new Cedar action</figcaption></figure><h3>Step 3: Create Policies</h3><ol><li>Go to Manage Policy Store &gt; Policies &gt; Add Policy &gt; Text Editor.</li><li>Copy policies one by one, add to the text editor, and save.</li></ol><ul><li><strong>Admin Policy</strong> (full access):</li></ul><pre>@id(&quot;AdminPerformAnyOperationOnResource&quot;)<br>permit(<br>  principal in Jans::Role::&quot;admin&quot;,<br>  action,<br>  resource<br>);</pre><ul><li><strong>Manager Policy</strong> (restricted access):</li></ul><pre>@id(&quot;ManagerCanAddUpdateViewTask&quot;)<br>permit (<br>  principal in Jans::Role::&quot;manager&quot;,<br>  action in [Jans::Action::&quot;Add&quot;,<br>  Jans::Action::&quot;Update&quot;,<br>  Jans::Action::&quot;View&quot;],<br>  resource is Jans::Task<br>);</pre><ul><li><strong>Member Policy</strong> (view only):</li></ul><pre>@id(&quot;MemberCanOnlyViewTask&quot;)<br>permit (<br>  principal in Jans::Role::&quot;member&quot;,<br>  action in [Jans::Action::&quot;View&quot;],<br>  resource is Jans::Task<br>);</pre><h3>Setting up a React Application</h3><h3>Step 1: Install the Cedarling WASM</h3><pre>npm install @janssenproject/cedarling_wasm</pre><p>For Vite.js, update vite.config.ts:</p><pre>import { defineConfig } from &quot;vite&quot;;<br><br>export default defineConfig({<br>  optimizeDeps: {<br>    exclude: [&quot;@janssenproject/cedarling_wasm&quot;],<br>  },<br>});</pre><h3>Step 2: Configure the Cedarling</h3><p>Initialize with these properties:</p><pre>export const cedarlingBootstrapProperties = {<br>  CEDARLING_APPLICATION_NAME: &quot;TaskManager&quot;,<br>  CEDARLING_POLICY_STORE_URI: &quot;&lt;your_policy_store_URI&gt;&quot;,<br>  CEDARLING_USER_AUTHZ: &quot;enabled&quot;,<br>  CEDARLING_LOG_TYPE: &quot;std_out&quot;,<br>  CEDARLING_LOG_LEVEL: &quot;INFO&quot;,<br>  CEDARLING_LOG_TTL: 120,<br>  CEDARLING_PRINCIPAL_BOOLEAN_OPERATION: {<br>    &quot;===&quot;: [{ var: &quot;Jans::User&quot; }, &quot;ALLOW&quot;],<br>  },<br>};</pre><ul><li>CEDARLING_POLICY_STORE_URI: URL of your policy store (from Agama-Lab). In the policy store list, use the link button to copy the policy store URI.</li></ul><h3>Step 3: Create Authorization Client</h3><p>This class implements a singleton pattern for managing Cedar authorization using WebAssembly (WASM), providing a centralized way to initialize the Cedar policy engine and perform authorization checks. It wraps the @janssenproject/cedarling_wasm module to handle policy evaluation through a single, reusable instance that can be accessed throughout the application.</p><pre>class CedarlingClient {<br>  private static instance: CedarlingClient;<br>  private cedarling: Cedarling | null = null;<br>  private initialized = false;<br>  private wasmModule: any = null;<br><br>  private constructor() {}<br><br>  static getInstance(): CedarlingClient {<br>    if (!CedarlingClient.instance) {<br>      CedarlingClient.instance = new CedarlingClient();<br>    }<br>    return CedarlingClient.instance;<br>  }<br><br>  async initialize(policyStoreConfig: any): Promise&lt;void&gt; {<br>    if (!this.initialized) {<br>      this.wasmModule = await initWasm();<br>      console.log(&quot;WASM initialized&quot;, this.wasmModule);<br>      this.cedarling = (await init(policyStoreConfig)) as unknown as Cedarling;<br>      this.initialized = true;<br>    }<br>  }<br><br>  async authorize(request: any): Promise&lt;AuthorizeResult&gt; {<br>    if (!this.cedarling || !this.initialized) {<br>      throw new Error(&quot;Cedarling not initialized&quot;);<br>    }<br>    try {<br>      const result = await this.cedarling.authorize(request);<br>      return result;<br>    } catch (error) {<br>      console.error(&quot;Error during authorization:&quot;, error);<br>      throw error;<br>    }<br>  }<br>}<br><br>export const cedarlingClient = CedarlingClient.getInstance();</pre><h3>Step 4: Initialize Cedarling</h3><p>We are globally initializing the Cedarling object. You can add it to your app’s startup files. Like in the ViteJS case, you can add it in App.tsx, and in the Next JS case, you can add it in src/layout.tsx.</p><pre>useEffect(() =&gt; {<br>  cedarlingClient.initialize(cedarlingBootstrapProperties).catch(console.error);<br>}, []);</pre><h3>Step 5: React Hook for Authorization</h3><p>This Reack hook provides authorization functionality using the Cedarling client, with the ability to enforce authorization checks when enabled through environment variables. The hook manages loading and error states while processing authorization requests, and returns a boolean or AuthorizeResult indicating whether the authorization was successful.</p><pre>import { useCallback, useState } from &quot;react&quot;;<br>import { cedarlingClient } from &quot;./cedarlingUtils&quot;;<br>import { parseJwt } from &quot;./parseJWT&quot;;<br>import { AuthorizeResult } from &quot;@janssenproject/cedarling_wasm&quot;;<br><br>export function useCedarling() {<br>  const [isLoading, setIsLoading] = useState(false);<br>  const [error, setError] = useState&lt;Error | null&gt;(null);<br>  const authorize = useCallback(<br>    async (request: any): Promise&lt;AuthorizeResult&gt; =&gt; {<br>      setIsLoading(true);<br>      setError(null);<br>      try {<br>        // debug logs<br>        console.log(&quot;Enforcing Cedarling authorization&quot;);<br>        console.log(&quot;Request: &quot;, request);<br>        console.log(&quot;Decoded idToken: &quot;, parseJwt(request.tokens.id_token as string));<br>        console.log(&quot;Decoded accessToken: &quot;,parseJwt(request.tokens.access_token as string));<br>        // userinfo token case<br>        // console.log(&#39;Decoded userInfo: &#39;, parseJwt(request.tokens.userinfo_token as string))<br>        return await cedarlingClient.authorize(request);<br>      } catch (err) {<br>        const error = err instanceof Error ? err : new Error(&quot;Authorization failed&quot;);<br>        setError(error);<br>        throw error;<br>      } finally {<br>        setIsLoading(false);<br>      }<br>    },<br>    []<br>  );<br>  return { authorize, isLoading, error };<br>}</pre><h3>Step 6: Protect Actions and Components</h3><p>Use React Hooks to protect actions and components. Your ID Token should have a role claim. It can be one value, like role: admin or an array, like role: [&quot;admin&quot;, &quot;manager&quot;]both are valid. Check the <a href="https://docs.jans.io/head/cedarling/cedarling-entities/">Cedarling entities document</a> for more details about role entity creation and usage.</p><p>Below is an example of the Task React Page:</p><pre>import { useCedarling } from &quot;@/factories/useCedarling&quot;;<br>import { AuthorizeResult } from &quot;@janssenproject/cedarling_wasm&quot;;<br><br>export default function TasksPage() {<br>  const { authorize } = useCedarling();<br><br>  const cedarlingRequest = async (action: string) =&gt; {<br>    const idToken = &quot;&lt;your_id_token&gt;&quot;;<br>    const accessToken = &quot;&lt;your_access_token&gt;&quot;;<br><br>    const request = {<br>      tokens: {<br>        access_token: accessToken,<br>        id_token: idToken,<br>      },<br>      action: `Jans::Action::&quot;${action}&quot;`,<br>      resource: {<br>        type: &quot;Jans::Task&quot;,<br>        id: &quot;App&quot;,<br>        app_id: &quot;App&quot;,<br>        name: &quot;App&quot;,<br>        url: {<br>          host: &quot;jans.test&quot;,<br>          path: &quot;/&quot;,<br>          protocol: &quot;http&quot;,<br>        },<br>      },<br>      context: {},<br>    };<br><br>    const result: AuthorizeResult = await authorize(request);<br>    return result;<br>  };<br><br>  const handleAdd = async () =&gt; {<br>    try {<br>      const result = await cedarlingRequest(&quot;Add&quot;);<br>      console.log(result);<br>      if (result.decision) {<br>        alert(&quot;Successfully added!&quot;);<br>      } else {<br>        alert(&quot;You are not allowed to add new Task!&quot;);<br>      }<br>    } catch (e) {<br>      alert(&quot;You are not allowed to add new Task!&quot;);<br>      console.log(e);<br>    }<br>  };<br>}<br><br>&lt;button className=&quot;btn btn-primary mb-3&quot; onClick={handleAdd}&gt;<br>  &lt;FaPlus className=&quot;me-2&quot; /&gt;<br>  Add Task<br>&lt;/button&gt;;</pre><p>In the above example, there are 2 things:</p><ul><li>First, we make a function cedarlingRequest which accepts an action and helps us to make an authorization request to the Cedarling WASM with Access Token and ID Token. Your ID Token should have a Role claim, and if you don&#39;t have a role, then you need to change the policy, which will act like ABAC.</li><li>Second, we have the handleAdd function, which helps us to request and check the authorization for the Add operation. In response, it returns a result where we get which policy is responsible for authorization, timestamp, and decision. Below is an example of the result. Use result.decision to authorize the request and show/hide elements.</li></ul><pre>{<br>  &quot;id&quot;: &quot;0196118a-ce6e-74c8-9c25-5da154aa8b90&quot;,<br>  &quot;request_id&quot;: &quot;0196118a-ce6a-7653-b64c-e5fb9722c1d1&quot;,<br>  &quot;timestamp&quot;: &quot;2025-04-08T00:07:11.662Z&quot;,<br>  &quot;log_kind&quot;: &quot;Decision&quot;,<br>  &quot;policystore_id&quot;: &quot;87d2c8877a2455a16149c55d956565e1d18ac81ba10a&quot;,<br>  &quot;policystore_version&quot;: &quot;undefined&quot;,<br>  &quot;principal&quot;: [&quot;User&quot;],<br>  &quot;User&quot;: {},<br>  &quot;diagnostics&quot;: {<br>    &quot;reason&quot;: [<br>      {<br>        &quot;id&quot;: &quot;6b51f8244fe1fc3b273733f9d93def7f07080367fbc1&quot;,<br>        &quot;description&quot;: &quot;ManagerCanAddUpdateViewTask&quot;<br>      }<br>    ],<br>    &quot;errors&quot;: []<br>  },<br>  &quot;action&quot;: &quot;Jans::Action::\&quot;Add\&quot;&quot;,<br>  &quot;resource&quot;: &quot;Jans::Task::\&quot;App\&quot;&quot;,<br>  &quot;decision&quot;: &quot;ALLOW&quot;,<br>  &quot;tokens&quot;: {<br>    &quot;id_token&quot;: {<br>      &quot;jti&quot;: &quot;J4TB2NsgTZOBtPTYTzHtmg&quot;<br>    },<br>    &quot;access_token&quot;: {<br>      &quot;jti&quot;: &quot;hNhnQW18RA2AIOh5ihOfTQ&quot;<br>    }<br>  },<br>  &quot;decision_time_micro_sec&quot;: 3000,<br>  &quot;pdp_id&quot;: &quot;bbcf165b-1b7b-452a-af46-b9dbf3ae7cf0&quot;,<br>  &quot;application_id&quot;: &quot;AgamaLab&quot;<br>}</pre><p>Like we handled the Add action, you can handle other actions and show hide components.</p><h3>Step 7: Protecting UI Components</h3><p>This ProtectedSection component is a React wrapper that controls access to UI components based on user authorization. It takes a resource ID and optional action ID, checks if the user has permission to access that resource using Cedar authorization, and either displays the protected content (children) if authorized or shows a fallback component (typically an error message) if access is denied.</p><pre>import { useCedarling } from &quot;@/factories/useCedarling&quot;;<br>import React from &quot;react&quot;;<br><br>export function ProtectedSection({<br>  accessToken,<br>  idToken,<br>  actionId,<br>  resourceId,<br>  children,<br>  fallback = (<br>    &lt;div&gt;<br>      &lt;div&gt;Access Denied&lt;/div&gt;<br>      {`Please contact your administrator.`}<br>    &lt;/div&gt;<br>  ),<br>  loadingFallback = &lt;div&gt;Loading...&lt;/div&gt;,<br>}: ProtectedSectionProps) {<br>  const { authorize, isLoading, error } = useCedarling();<br>  const [isAuthorized, setIsAuthorized] = React.useState(false);<br><br>  React.useEffect(() =&gt; {<br>    const checkAuthorization = async () =&gt; {<br>      const request = {<br>        tokens: {<br>          access_token: accessToken,<br>          id_token: idToken,<br>        },<br>        action: `Jans::Action::&quot;${actionId}&quot;`,<br>        resource: { type: &quot;Jans::Task&quot;, id: resourceId, name: resourceId },<br>        context: {},<br>      };<br>      try {<br>        const result = await authorize(request);<br>        setIsAuthorized(result.decision);<br>      } catch (err: any) {<br>        setIsAuthorized(false);<br>      }<br>    };<br>    checkAuthorization();<br>  }, [accessToken, idToken, authorize, actionId, resourceId]);<br><br>  if (isLoading) return &lt;&gt;{loadingFallback}&lt;/&gt;;<br>  if (error) return &lt;div&gt;Error: {error?.message}&lt;/div&gt;;<br>  if (!isAuthorized) return &lt;&gt;{fallback}&lt;/&gt;;<br>  return &lt;&gt;{children}&lt;/&gt;;<br>}</pre><p>Use ProtectedSection to protect any elements. Your ID Token should have a role claim. It can be one value, like role: admin or an array like role: [&quot;admin&quot;, &quot;manager&quot;, &quot;member&quot;]both are valid. Check the <a href="https://docs.jans.io/head/cedarling/cedarling-entities/">Cedarling entities document</a> for more details about role entity creation and usage.</p><pre>&lt;ProtectedSection<br>  accessToken={accessToken}<br>  idToken={idToken}<br>  resourceId=&quot;App&quot;<br>  actionId=&quot;Delete&quot;<br>&gt;<br>  &lt;h1&gt;Welcome, permission granted!&lt;/h1&gt;<br>&lt;/ProtectedSection&gt;</pre><h3>Test Cases</h3><h3>Admin Authorization</h3><p>Let’s log in as an <strong>admin</strong> user and check the authorization. As per the above authorization policies, admins can access any resource. As you can see in the video below, Sachin is an admin user, and he has the admin role in ID Token.</p><p>🟢 Admin can Add a task</p><p>🟢 Admin can Update a task</p><p>🟢 Admin can Delete a task</p><p>🟢 Admin can view a task</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2FaxDsoPvuiV0%3Ffeature%3Doembed&amp;display_name=YouTube&amp;url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DaxDsoPvuiV0&amp;image=https%3A%2F%2Fi.ytimg.com%2Fvi%2FaxDsoPvuiV0%2Fhqdefault.jpg&amp;type=text%2Fhtml&amp;schema=youtube" width="640" height="480" frameborder="0" scrolling="no"><a href="https://medium.com/media/6cc7b6e81e4bc0d2dcc6aa115fd5e812/href">https://medium.com/media/6cc7b6e81e4bc0d2dcc6aa115fd5e812/href</a></iframe><h3>Manager Authorization</h3><p>Log in with a <strong>manager</strong> role user and check the authorization. As per our authorization policies, a manager cannot perform the `Delete` action.</p><p>🟢 Manager can Add a task</p><p>🟢 Manager can Update a task</p><p>🟢 Manager can view a task</p><p>🔴 Manager cannot Delete a task</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2FRgTaI-z6VMY%3Ffeature%3Doembed&amp;display_name=YouTube&amp;url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DRgTaI-z6VMY&amp;image=https%3A%2F%2Fi.ytimg.com%2Fvi%2FRgTaI-z6VMY%2Fhqdefault.jpg&amp;type=text%2Fhtml&amp;schema=youtube" width="640" height="480" frameborder="0" scrolling="no"><a href="https://medium.com/media/935f5a9b34b555ca024ceaabe146aa4c/href">https://medium.com/media/935f5a9b34b555ca024ceaabe146aa4c/href</a></iframe><h3>Member Authorization</h3><p>Log in with a <strong>member</strong> role user and check the authorization. As per our authorization policies, members can only `view` tasks.</p><p>🟢 Member can view a task</p><p>🔴 Member cannot Add a task</p><p>🔴 Member cannot Update a task</p><p>🔴 Member cannot view a task</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2FO4sgR1xZSqg%3Ffeature%3Doembed&amp;display_name=YouTube&amp;url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DO4sgR1xZSqg&amp;image=https%3A%2F%2Fi.ytimg.com%2Fvi%2FO4sgR1xZSqg%2Fhqdefault.jpg&amp;type=text%2Fhtml&amp;schema=youtube" width="640" height="480" frameborder="0" scrolling="no"><a href="https://medium.com/media/7023c7c3ec30f884f4744271d0ecd7e6/href">https://medium.com/media/7023c7c3ec30f884f4744271d0ecd7e6/href</a></iframe><h3>Key Takeaways</h3><ul><li>The Janssen Cedarling provides fine-grained RBAC for React apps.</li><li>Easy to protect components and limit user access. Use ProtectedSection to restrict UI elements.</li><li>Policy management is centralized via Agama Lab.</li></ul><p>For a complete implementation, reference the:</p><ul><li><a href="https://github.com/GluuFederation/tutorials/tree/master/cedarling/react/next-js-cedarling">Next JS Demo project</a></li><li><a href="https://github.com/GluuFederation/tutorials/blob/master/cedarling/react/next-js-cedarling-policy-store/87d2c8877a2455a16149c55d956565e1d18ac81ba10a.json">Policy Store</a></li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=1d449f6b4840" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>