How to debug role permisions?

In an effort to understand Fauna better I’m reconstruction the wonderful Fauna Auth Skeleton by hand. I’ve this slightly modified login function:

{
  name: "login_new",
  role: null,
  body: Query(
    Lambda(
      ["email", "password"],
      Let(
        {
          maxFailedLogins: Call("config_var", {
            path: ["rate_limiting", "failed_logins", "max"]
          }),
          rateLimitFailedLogins: Call("config_var", {
            path: ["rate_limiting", "failed_logins", "enabled"]
          }),
          logLogins: Call("config_var", { path: ["logging", "login"] })
        },
        Do(
          If(
            Var("rateLimitFailedLogins"),
            Call("call_limit", [
              "failed_login",
              Var("email"),
              Var("maxFailedLogins")
            ]),
            false
          ),
          Let(
            {
              loginResult: If(
                Exists(Match(Index("accounts_by_email"), Var("email"))),
                If(
                  Identify(
                    Select(
                      ["ref"],
                      Get(Match(Index("accounts_by_email"), Var("email")))
                    ),
                    Var("password")
                  ),
                  Let(
                    {
                      account: Get(
                        Match(Index("accounts_by_email"), Var("email"))
                      ),
                      accountRef: Select(["ref"], Var("account")),
                      tokens: Let(
                        {
                          refresh: Create(Tokens(), {
                            instance: Var("accountRef"),
                            data: {
                              type: "refresh",
                              used: false,
                              sessionId: If(
                                And(
                                  HasCurrentToken(),
                                  Equals(
                                    Select(
                                      ["data", "type"],
                                      Get(CurrentToken()),
                                      false
                                    ),
                                    "refresh"
                                  )
                                ),
                                Select(
                                  ["data", "sessionId"],
                                  Get(CurrentToken())
                                ),
                                NewId()
                              ),
                              validUntil: TimeAdd(
                                Now(),
                                Call("config_var", {
                                  path: [
                                    "session",
                                    "refresh_tokens",
                                    "lifetime_seconds"
                                  ]
                                }),
                                "seconds"
                              ),
                              loggedOut: false
                            },
                            ttl: TimeAdd(
                              Now(),
                              Call("config_var", {
                                path: [
                                  "session",
                                  "refresh_tokens",
                                  "reclaimtime_seconds"
                                ]
                              }),
                              "seconds"
                            )
                          }),
                          access: Create(Tokens(), {
                            instance: Var("accountRef"),
                            data: {
                              type: "access",
                              refresh: Select(["ref"], Var("refresh"))
                            },
                            ttl: TimeAdd(
                              Now(),
                              Call("config_var", {
                                path: [
                                  "session",
                                  "access_tokens",
                                  "lifetime_seconds"
                                ]
                              }),
                              "seconds"
                            )
                          })
                        },
                        { refresh: Var("refresh"), access: Var("access") }
                      )
                    },
                    {
                      tokens: Var("tokens"),
                      account: Var("account"),
                      accessTokenLifetimeSeconds: Call("config_var", {
                        path: ["session", "access_tokens", "lifetime_seconds"]
                      })
                    }
                  ),
                  { errors: ["Wrong password."] }
                ),
                { errors: ["No account or incorrect email/password."] }
              )
            },
            If(
              Equals(Var("loginResult"), false),
              Do(
                If(
                  Var("logLogins"),
                  Call("log", ["auth", "login", Var("email")]),
                  false
                ),
                false
              ),
              Do(
                If(
                  Var("logLogins"),
                  Call("log", ["auth", "login", Var("email")]),
                  false
                ),
                If(
                  Var("rateLimitFailedLogins"),
                  Call("reset_access_logs", ["failed_login", Var("email")]),
                  false
                ),
                Var("loginResult")
              )
            )
          )
        )
      )
    )
  )
}

To which I assigned a role with the following permissions:



When I try to invoke it from the backend it yells at me:

{
  "errors":
  [
    {
      "position":[],
      "code":"call error",
      "description":"Calling the function resulted in an error.",
      "cause":
        [
          {
            "position":
              [
                "expr","in","do",1,"let","loginResult","then","then","let","tokens","let","refresh","params","object","data","object","sessionId","if","and",1,"equals",0,"from"
              ],
              "code":"permission denied",
              "description":"Insufficient privileges to perform the action."
          }
        ]
    }
  ]
}

The documentation states that:

User-defined functions (UDFs) can be created to have a role, such as role: "admin" . This allows UDFs to execute with specific privileges, which might be higher than those of the caller.

And when I assign the Admin role everything works just fine. But I can’t figure out which exact permissions I need here without the elevated access that Admin role grants to the function.

I would greatly appreciate couple of pointers on how to better understand the permission error messages and some debugging tips!

From the error, it looks like it is failing precisely at the expression Get(CurrentIdentity()) here:

                              sessionId: If(
                                And(
                                  HasCurrentToken(),
                                  Equals(
                                    Select(
                                      ["data", "type"],
                                      Get(CurrentToken()), // <---
                                      false
                                    ),
                                    // ...

This means that the Token does not have read access to whatever Collection the token belongs to. Either the permission for reading the accounts Collection is not set at the same time you are making queries, or the token used to call the UDF has an instance in a different Collection.

It’s been a while since my head was in the skeleton examples. If I understand correctly, the verification tokens and password-reset tokens come from other Collections. Do those call login?

This means that the Token does not have read access to whatever Collection the token belongs to. Either the permission for reading the accounts Collection is not set at the same time you are making queries, or the token used to call the UDF has an instance in a different Collection.

This precisely. Got it sorted in the end. Thanks!

1 Like

This topic was automatically closed 2 days after the last reply. New replies are no longer allowed.