Progressive Permissions with Webnative

Progressively asking the user for extra permissions is a pattern we want to establish and standardize for most fission-powered apps and it has been a much requested feature.

However, it’s actually already possible with the webnative building blocks there are today! (Webnative version 0.23.2 that is)

Unfortunately, it’s still quite invovled, which is why not everyone is doing it. We’ll improve the API in the future, but in the mean time, here’s a tutorial for how to progressively ask for permissions with webnative:

import * as webnative from "webnative"
// We use lodash/merge for merging permission JSON objects
import lodashMerge from "lodash/merge"


// The permission baseline is the minimum permissions we need for running the app
// I.e. what we want to *always* have access to, if webnative.initialise successfully authenticated
const permissionBaseline = {
    app: {
        creator: "matheus23",
        name: "progressive-permissions",
    },
}

// Let's make working with localStorage easier for us

function lookupLocalStorage(key) {
    const saved = localStorage.getItem(key)
    try {
        return JSON.parse(saved)
    } catch (_) {
        return null
    }
}

function saveLocalStorage(key, json) {
    localStorage.setItem(key, JSON.stringify(json, null, 2))
}


// We have two things we possibly store in localStorage:
// * permissions confirmed: Permissions we're pretty sure we already have
// * permissions wanted:    Permissions we _just_ asked for in the auth lobby before

const permissionsConfirmedKey = "permissions-confirmed-v1"
const lookupPermissionsConfirmed = () => lookupLocalStorage(permissionsConfirmedKey)
const savePermissionsConfirmed = json => saveLocalStorage(permissionsConfirmedKey, json)

const permissionsWantedKey = "permissions-wanted-v1"
const lookupPermissionsWanted = () => lookupLocalStorage(permissionsWantedKey)
const savePermissionsWanted = json => saveLocalStorage(permissionsWantedKey, json)

// If the user denied the request for more permissions, we reset the wanted permissions
const url = new URL(window.location.href)
if (url.searchParams.get("cancelled") != null) {
    savePermissionsWanted(null)
}

const permissionsConfirmed = lookupPermissionsConfirmed() || {}
const permissionsWanted = lookupPermissionsWanted() || {}

// We now merge the baseline with what we know we already should have and what we want to enable additionally.
// This is essentally the heart of it all
const permissions = lodashMerge(permissionBaseline, permissionsConfirmed, permissionsWanted)


// We now know with which permissions to initialise webnative

webnative.initialise({ permissions })
    .then(state => {
        if (state.authenticated) {
            // We now know that this is the permissions we have
            // and we'll request the same permissions next time
            savePermissionsConfirmed(permissions)
        } else {
            // We actually don't have the permissions we expect to
            // so we reset what we know to zero
            savePermissionsConfirmed(null)

            // This is also the case we run into if the user hasn't authenticated yet.
            // So we do that.
            webnative.redirectToLobby(permissionsBaseline)
        }
        // There should be no further permissions we want to request in the future.
        // We either just got them, or we've got them denied. In any case we stop trying.
        savePermissionsWanted(null)

        // ... Initialise our app
    })

// If we ever want more permissions, we call this function:
async function requestAdditionalPermissions(permissions) {
    // We make sure that we actually initialise webnative with the
    // additional permissions the next time we open the page
    // (which is hopefully after the user accepted the permissions)
    savePermissionsWanted(permissions)
    await webnative.redirectToLobby(permissions)
}

// We can use it like this
await requestAdditionalPermissions({
    fs: { privatePaths: ["Images/"] }
})

Feel free to comment your thoughts :+1:

3 Likes

This looks really great in general. The revamp work is going to need to include an auth store, because keeping this stuff straight is harder than it seems initially. Any other learnings form doing the above would be appreciated as well :slight_smile:

2 Likes

Having upgraded the fission client last week,
Progressive Permissions came to the fore as much as
questions related to progressive account and private sharing

Thanks for a nice treatment.
Good ideas live by being stolen, they die when they are not recognized.