Permission Plugin

Building your own permission plugin

Learn the basics of creating a permission plugin, allowing you to allow or deny actions down to a per message basis.

You can see the code for this here

Configuring the plugin

  1. Via config.yml:
    permission:
        path: './permission/username-permission'
  2. Via deepstream constructor:
    import { Deepstream } from '@deepstream/server'
    
    export const deepstream = new Deepstream({
        permission: {
            path: './permission/username-permission',
            options: {}
        }
    })
    
    deepstream.start()
  3. Via deepstream setter:
    import { Deepstream } from '@deepstream/server'
    import UsernamePermission from './username-permission'
    
    const deepstream = new Deepstream({})
    
    deepstream.set('permission', new UsernamePermission({}, deepstream.getServices()))
    
    deepstream.start()

Example Documented Plugin

import { DeepstreamPlugin, DeepstreamServices, DeepstreamPermission, PermissionCallback, SocketWrapper } from '@deepstream/types'
import { Message } from '@deepstream/protobuf/dist/types/messages';

interface UsernamePermissionOptions {
}

export default class UsernamePermission extends DeepstreamPlugin implements DeepstreamPermission {
    public description = 'Header Authentication';
    private logger = this.services.logger.getNameSpace('USERNAME_PERMISSION')

    constructor (private pluginOptions: UsernamePermissionOptions, private services: Readonly<DeepstreamServices>) {
        super()
    }

    /**
     * The permission API is more functional due to the performance implications in deepstream, hence we path through alot of the data! This 
     * also allows you to go a bit crazy with implementations.
     * 
     * Whats important is you return an error or valid callback per permission, and keep in mind event though it is async you really want this
     * to be as quick and lightweight as possible!
     * 
     * You have full access to the message via the `message` object and `authData` which is the `serverData` returned via the authentication plugin.
     */
    canPerformAction(socketWrapper: SocketWrapper, message: Message, callback: PermissionCallback, passItOn: any): void {
        // In this example just check that there is a name to the message and it contains the username. This is a very naive example as it means the user
        // can't invoke RPCs and scopes all realtime interaction to just one client. However if you used `authData.orgName` this would allow you to do multi-tenancy
        // permissions!
        if (message.name && message.name.includes(socketWrapper.userId)) {
            callback(socketWrapper, message, passItOn, null, true)
            return
        }

        callback(socketWrapper, message, passItOn, "Error, name doesn't include the username or message doesn't have a name", false)
    }
}