For a business requirements see User management.

There are two dimensions of access control in the backoffice

  1. Every user is part of a team (group), granting them permissions to access some features

  2. Every user has a role, which further affects what they can do

The access control is defined in Okta identity manager.

1. Groups and permissions

The backoffice teams are modelled in Okta as “groups”, so going forward they will be called “groups” here.

The source of truth for groups and their permissions is call Access Matrix and is in Lark

The info from the Business matrix is converted into the Technical matrix by hand. Make sure the business people know that and do not edit the matrix without telling the devs.

Also the mapping is not 1-to-1 but attributes with same right are grouped to keep the permissions system simpler.

Team name

Technical group name

Developers
(not a real team, used for development)

developers

Important: we presumably don’t want to have this role in production (?).

Payments and Card OPS Team

payments-cards

CDD Team

customer-due-diligence

CC Team

call-center

Telesales Team

telesales

Sales Team

sales

Collections Team

collections

Risk - Underwriting Team

risk-underwriting

Risk - AntiFraud Team

risk-antifraud

Okta has separate groups for each environment with the group names in format

bofe-{environment}-{technical group name}

For example: bofe-brave-developers, bofe-brave-risk-underwriting, bofe-stage-sales

In the day-to-day bank operation it is expected that each user will belong to one team/group.

However, the system allows users to belong to any number of groups (gaining permission of all the groups).

Permissions

As seen in the access matrix, each group gives certain permissions to its users.

In the (real-world) example below:

  • Everyone can view customer profile and customer address

  • Only Customer due diligence (CDD) team can edit the customer profile

  • Only CDD, Call center and Sales teams can edit the customer address

These permissions strings are used in both BE and FE to restrict what users can see and do.

Adding/removing/updating permissions

To update permissions use the Permission migration generator to generate a migration for the user_group_permissions table. First. you should export the technical access matrix tab as a CSV.

Checking for permission in backoffice-manager BE

To check the permission use @BankUserOnly to get the bank user that is calling the endpoint and verifyUserHasPermission to test for certain permission.

In this example, we check if the user can view details of the “main account” of a customer:

@Get(uri = "/main-account/by-customer/{ownerId}", produces = ["application/json"])
@BankUserOnly
fun getMainAccountByCustomer(ownerId: UUID, bankUser: BankUserAuthentication): AccountV2Dto {
    val bankUserDto = iamDefaultApiClient.getUser(bankUser.uid)
    userAuthorizationService.verifyUserHasPermission(
        bankUserDto,
        UserPermission.MAIN_ACCOUNT_VIEW
    )
    return mainAccountApiClient.getMainAccountByCustomer(ownerId) ?: 
        throw AccountNotFoundException("Account for owner id $ownerId not found")
}

Checking for permission in app-bo FE

To check if the current user has certain permission use the usePermission hook.

It has two modes of use

  • To check just single permission

    const { isAllowed } = usePermission('CUSTOMER_EMPLOYEE_FLAG_UPDATE')
  • To check multiple permissions

    const { allows } = usePermission()
    cosnt isAllowed = allows('CUSTOMER_EMPLOYEE_FLAG_UPDATE') // synchronous

Frequently you want to hinder some component(s) when the user does not have some permission, for this PermissionGuard component can be used like so:

<PermissionGuard permission="DOCUMENT_UPLOAD">
  <CustomButton onClick={handleOpen}>
    {t('uploadButton')}
  </CustomButton>
</PermissionGuard>

Another notable helper is getRoutePermission.

The access matrix is changing very rarely, so once the FE fetches the permissions for the first time it caches them forever (until the page is closed or refreshed).

2. Roles

The user’s role is determined by how the user’s profile is set up directly in Okta (see https://safibank.atlassian.net/wiki/spaces/ITArch/pages/122322947/IAM+for+Back+Office#Specifying-checkers). Every user can have 1 other user set as “Checker” in Okta.

  • The user is considered to have a “Maker role” if he/she has a Checker set

  • The user is considered to have a “Checker role” if he/she is set as Checker of somebody

This means that a user can be both or neither.

The single attribute on Okta is really all there is, there is no “role” attribute anywhere.

There is a getUser endpoint that contains his resolved into isMaker and isChecker attributes.

There is also getCheckersForUser endpoint to all checkers for a user (i.s. user’s checker, that checker’s checker (if present) etc.)

There is no simple way to find the reverse - all users someone is checker of.

For more info about the maker-checker process see Maker-checker flows

In the day-to-day bank operation it is expected there will be in each team

  • Several “makers”, standard employees

  • One team supervisor as their direct checker, but also maker

  • Section head, direct checker of the team supervisor (but able to check also employees)

However the system is build to support also longer and bigger hierarchies.
Also nothing prevents the maker and his/her checker to be in different teams/groups, but in correct setup this is not supposed to happen.

The distinction behind the two roles is as follows:

Maker

Checker

None

Can view customer data

Yes

Yes

Yes

Can modify customer data

Yes

No

No

Can approve/reject customer data modifications

No

Yes

No

This is on top of the permissions granted by groups!
So to modify X, a user need to have both “Maker role” AND be in agroup that grants X_UPDATE permission.

So in this example

  • Everyone can view the customer profile, regardless of group or role

  • Customer due diligence (CDD) users that have “Maker role” can edit customer profile

  • Other CDD users (“Checker” or no role) cannot edit customer profile (permitted by the group but, not by role)

  • No Call center users can edit customer profile (even “Makers”, as their group does not permit it)

Adding/removing the role

As mentioned this, is done in Okta

  • To add “Marker role” to a user, set Checker in the profile of that user

    • Unset to remove

  • To add “Checker role” to a user, set that user as Checker os someone else

    • Unset the user from all makers to remove

Checking for roles in backoffice-manager BE

  • For makers use UserAuthorizationService.verifyUserIsMaker helper

  • For checkers we only check if they can approve/reject a change and for that a Change.allowedCheckerIds is used directly (see Maker-checker flows)

Checking for roles in backoffice-manager FE

  • For makers, this is done automatically by the usePermission hook which allows only the permissions that match NON_MAKER_SUFFIXES for users that are not makers.

  • For checkers, we use a more fine-grained check as every Change includes an explicit list of allowedCheckerIds and only if the current user is one of them the approve/reject change buttons are shown. (see Maker-checker flows)

The isMaker and isChecker attributes are present in the user produced by useUserInfo() hook if needed for other purposes or some special checks.