Me On IT
Published on

Protected Areas

Authors

Today we're getting our hands dirty, delving into the technical details in the context of our Distributed Digital ID. Our users identify themselves -- as already explained -- through their Ethereum address, with which they can create signatures. Registration is no longer necessary. The provision of personal data is omitted, not even an email address needs to be specified.

First, we need a permission system to assign rights to each user. For this example, we made life easy for ourselves and chose a very simple Node module: AccessControl

We replace the Ethereum addresses with constants that represent individual users, and then we can write:

    // file BlogAccessControl

    import { AccessControl } from 'accesscontrol'

    const blogOwner: string = '0x... '
    const coach: string = '0x...'
    const coachesNFrensResource: string = 'coachesnpartners'
    const privateResource: string = 'private'
    const obj = new AccessControl()


    obj
    .grant(coach)
    .readAny(coachesNFrensResource)
    .grant(blogOwner)
    .extend(coach)
    .readAny(privateResource)

    export default {
    ac: obj,
    }

This concisely defines a private area and a second one reserved for business partners and coaches. The blog owner can view both areas, a coach only one.

Now it gets really tricky: We have to check the permissions in such a way that the areas are secure.

As explained in the last post, the permissions are to be proven via a JWT. This achieves potential interoperability with all areas where JWTs are already used.

So, we have the following dependencies:

import jwt from 'jsonwebtoken'
import BlogAccessControl from 'BlogAccessControl'

... and then we can write:



function validateRights (cookies, rights: string | null) {
    const bearerToken = cookies.get('cookiename')?.value
    const secretKey = process.env.JSON_WEBTOKEN_SECRET

    try {
      const decoded = jwt.verify(bearerToken, secretKey)
      if (rights) {
             const permissions =
              BlogAccessControl.ac.
               can(decoded.address).
                 readAny(rights)
        [...]
      } else {
        [...]
      }

    } catch (e) {
        [...]
    }
  }

In this case, we also differentiate the scenario where an ETH address is used for login, but it is not known and therefore not equipped with special rights.

Also noteworthy: We have a Next.js application here, so parts of the application are executed in the browser, others on a backend server. The verification of the JWT must be carried out on the backend, as it requires the key used when generating the token.

For our example, a blog, it only makes sense if the authorization takes place on the backend, otherwise blog entries might be viewed without authorization. Of course, that's not what we want.

Well then! There are a few less important pitfalls that need to be overcome, but in the end, it works like this, and that's why I won't go into further detail.

My blog is based on this very powerful template by Timothy Lin

It is also worth mentioning that Contentlayer is used to hold the blog entries on the backend and load them into the browser as needed. Those interested in how access rights can be validated in this context are welcome to contact me. I would be happy to write more on the topic.