Impersonate database access

You can write applications that impersonate database access using a key that you already have. For example, you might want to impersonate database access when:

  • You have a reporting tool that needs to gather information from all of your child databases.

  • Your application makes queries on behalf of users, and you want to test that features or access controls are working correctly but you don’t have access to user passwords.

  • Your application has different capabilities for users with differing roles, and you want to test the capabilities and access controls.

For these use cases, Fauna accepts a scoped key. A scoped key uses a secret that you already have to impersonate access to Fauna. A scoped key can only impersonate the same or lesser level of privileges. You cannot use a scoped key to gain more privileges.

If you completed the Child database access, you have already used scope keys when you used the Dashboard Shell run menu. You can use this feature to run a query using different built-in roles:

Menu Description

Admin

Equivalent to using a key with the admin role. This is the default setting.

Server

Equivalent to using a key with the server role.

Secret

Use an existing key secret

You can also use run a query as a user-defined Role or an identity by choosing the Document option. More about the last two options in another tutorial. This tutorial focuses on key secrets.

After you select a run menu option, that selection applies to the current database. Subsequent queries that you execute in the Dashboard Shell run under your selected option. When you change to a new child database or database, you return to the default, which is to run as Admin.

Investigate with key scopes

If you worked through from the beginning of the Access control cookbook cookbook, you should have a list of key secrets for the following:

Key name Role Created on Access to

coffee-admin

admin

CoffeeStore

Full hierarchy

coffee-server

server

CoffeeStore

Full hierarchy

None.

admin

CoffeeStore/internal

internal hierarchy

None.

admin

CoffeeStore/production

production hierarchy

None.

server

CoffeeStore/internal

internal/bulletinBoard

None.

server

CoffeeStore/internal

internal/personnel

In a database, Fauna lists only the immediate resources available to that caller regardless of the credentials. A parent admin secret can connect to and manage any child database resources. These same rules apply for any connected application.

Investigate the practical implications of this in the Shell. Using the Database.all() do the following

  1. In the dashboard, make sure you are still in the CoffeeStore/internal database.

  2. Switch to the CoffeeStore/internal/personnel database

  3. Use the run menu Secret option to run the Database.all() query with each of these secrets:

    • coffee-admin

    • coffee-server

    • admin secret for the CoffeeStore/internal database

    • admin secret for the CoffeeStore/production database

  4. Switch to another database in the hierarchy and try these same secrets.

Add a scoped key an application

You already have two databases, production and internal, from the Child database access tutorial. If not, go to that section and create them. In this procedure, you change the simple coffeestore.mjs javascript program to use a scoped key.

  1. Open the coffeestore.mjs file you used in Keys and built-in roles.

  2. Add a scoped secret after the first envSecret definition.

    const envSecret = process.env.FAUNA_SECRET;
    
    const scoped_secret = `${envSecret}:production:admin`;

    The format of this scoped key is secret[:child_db]:role where:

    Field Description

    secret

    A key secret. An admin key is required to access a child database.`

    child_db

    Name of a child database. This is optional. When included, the secret for an admin key must be used. When not included, the secret from an admin or server key can be used.

    role

    The name of a built-in system role to use, one of admin, server, or server-readonly.

    This kind of scoped key is typically used to impersonate access to a child database. Given that scoped_secret uses the admin key, it allows full access to the production child database.

  3. Update the client configuration with the new scoped_secret.

    // Client that uses scoped key
    const client = new Client({ secret: scoped_secret, endpoint: new URL("https://db.fauna.com")});

    Your finished source should look like the following:

    import { Client, fql } from "fauna";
    
    const envSecret = process.env.FAUNA_SECRET;
    
    const scoped_secret = `${envSecret}:production:admin`;
    
    // const scopedClient = new Client({ secret: scoped_secret });
    const client = new Client({ secret: scoped_secret, endpoint: new URL("https://db.fauna.com")});
    
    try {
      // build queries using the fql function
      const collection_query = fql`Collection.create({ name: "Post" })`;
    
      // Execute the query, return more informative decorated format
      // The decorated format is not suitable for complex objects in production systems
      const collection_result = await client.query(collection_query, {format:
      "decorated"});
    
      console.log(collection_result);
    
      // define some data in your app
      const post = { headline: "Lost Doggo" };
    
      // query using your application local variables
      const document_query = fql`
      Post.create(${post}) {
          id,
          ts,
          headline
        }
      `;
      const document_result = await client.query(document_query);
      console.log(document_result);
    
    
    } catch (error) {
      console.log(error)
    }
  4. Save and close the application.

  5. Set the FAUNA_SECRET in your environment to the coffee-admin secret.

    export FAUNA_SECRET=“fnAFKPwOAtAAIYrsap-yiSh51Kc0g0AA6XQ4inqL”
  6. Run the application.

    node coffeestore.mjs

    You should see the Post and Lost Doggo document responses:

    {
      data: NamedDocument {
        coll: Module { name: 'Collection' },
        name: 'Post',
        ts: TimeStub { isoString: '2023-08-10T00:44:02.270Z' },
        data: {},
        indexes: {},
        constraints: []
      },
      static_type: 'CollectionDef',
      summary: '',
      txn_ts: 1691628242270000,
      stats: {
        compute_ops: 1,
        read_ops: 0,
        write_ops: 1,
        query_time_ms: 90,
        contention_retries: 0,
        storage_bytes_read: 1443,
        storage_bytes_write: 353,
        rate_limits_hit: []
      },
      schema_version: 0
    }
    {
      data: {
        id: '372631816002076705',
        ts: TimeStub { isoString: '2023-08-10T00:44:02.430Z' },
        headline: 'Lost Doggo'
      },
      static_type: '{ headline: Any, ts: Any, id: Any }',
      summary: '',
      txn_ts: 1691628242430000,
      stats: {
        compute_ops: 1,
        read_ops: 0,
        write_ops: 1,
        query_time_ms: 72,
        contention_retries: 0,
        storage_bytes_read: 221,
        storage_bytes_write: 213,
        rate_limits_hit: []
      },
      schema_version: 1691628242270000
    }
  7. Open the Fauna Dashboard and navigate to the production database.

  8. Confirm the Post exists with one document called Lost Doggo.

    production confirm

Other scope key formats

There are more scope key formats you can use in your applications. Familiarize yourself with them now. The cookbook uses one of them in a later tutorial.

Impersonate authenticated user

Format:

secret[:child_db]:@doc/collection/id

Field Description

secret

A key secret. An admin key is required to access a child database.`

child_db

Name of a child database. This is optional. When included, the secret for an admin key must be used. When not included, the secret from an admin or server key can be used.

collection

Name of a collection in the current database or if child_db is included, in the child database.

id

The document ID for the document to authorize as. Document IDs are string-encoded 64-bit integers.

This kind of scoped key is used to impersonate a user because the key has the same privileges as the authenticated user document, for example:

fnACysRJGIACAHiL_5f0UxHlPFIZgq876ptMNJ72:@doc/users/1234

Impersonate user by role

Format:

secret[:child_db]:@role/name

This kind of scoped key is used to impersonate a user with the privileges of the role.

Field Description

secret

A key secret. An admin key is required to access a child database.`

child_db

Name of a child database. This is optional. When included, the secret for an admin key must be used. When not included, the secret from an admin or server key can be used.

name

The name of a role to authorize as.

For example, this key has the same privileges as a member document with the developers role:

fnACysRJGIACAHiL_5f0UxHlPFIZgq876ptMNJ72:@role/developers

Is this article helpful? 

Tell Fauna how the article can be improved:
Visit Fauna's forums or email docs@fauna.com

Thank you for your feedback!