Skip to content

ServiceAccounts Module

Service accounts are a specialized type of user within an application, designed specifically for enabling secure and authorized service-to-service communication or API access. They are represented as User entities with a type set to SA (service account) and have their own roles and permissions, just like regular users.

The Service Account API provides a dedicated layer for managing service accounts, simplifying their creation, modification, and management. By using service accounts instead of regular user accounts, applications can maintain a clear separation between human users and automated processes, ensuring proper access control and reducing the risk of unauthorized actions.

Key Components

The module provides a set of reusable components that can be easily integrated into a NestJS project:

Service Accounts Service

The ServiceAccountsService is a specialized module within an application that handles the creation, modification, and management of service accounts.

Service Accounts Resolver

The ServiceAccountsResolver is a crucial component within a NestJS application that handles the GraphQL queries and mutations related to service accounts

Entity Inheritance

NestKit provide base classes that can be inherited and customized with your needs. For entities we use TypeORM TableInheritance.

How to install ServiceAccountsModule to my app

To create a ServiceAccountsModule in NestJS, you can follow these steps:

  1. Install the required dependencies for ServiceAccountsModule:

  2. Create a service-accounts folder in your project's src/modules directory.

  3. Inside the service-accounts folder, create a service-accounts.service.ts file and extends BaseServiceAccountsService from NestKit with the following code:

    ts
    // src/modules/service-accounts/service-accounts.service.ts
    
    import { BaseServiceAccountsService } from '@deeepvision/nest-kit/dist/modules/service-accounts';
    import { Injectable } from '@nestjs/common';
    import { UserToRole } from '../user-to-roles/user-to-role.entity';
    import { User } from '../users/user.entity';
    import { Organization } from '@/modules/organizations/organization.entity';
    
    @Injectable()
    export  class ServiceAccountsService extends BaseServiceAccountsService<User, UserToRole, Organization> {}
  4. Inside the service-accounts folder, create a service-accounts.resolver.ts file and extends BaseServiceAccountsResolver with the following code:

    ts
    // src/modules/serviceaccounts/service-accounts.resolver.ts
    
    import { Resolver } from '@nestjs/graphql';
    import { User } from '@/modules/users/user.entity';
    import { BaseServiceAccountsResolver } from '@deeepvision/nest-kit/dist/modules/service-accounts';
    import { UserToRole } from '../user-to-roles/user-to-role.entity';
    import { Organization } from '../organizations/organization.entity';
    
    @Resolver()
    export class ServiceAccountsResolver extends BaseServiceAccountsResolver<User, UserToRole, Organization>(User) {}
  5. Inside the service-accounts/service-tokens folder, create service-token.entity.ts file and extends BaseServiceToken with the following code:

    ts
    // src/modules/serviceaccounts/service-tokens/service-token.entity.ts
    
    import { BaseServiceToken } from '@deeepvision/nest-kit/dist/modules/service-accounts/service-tokens/service-token.entity';
    import { ObjectType } from '@nestjs/graphql';
    import { ChildEntity } from 'typeorm';
    import { User } from '@/modules/users/user.entity';
    
    @ObjectType()
    @ChildEntity()
    export class ServiceToken extends BaseServiceToken {
      user!: Promise<User>;
    }
  6. Inside the service-accounts/service-tokens folder, create service-tokens.service.ts file and extends BaseServiceTokensService with the following code:

    ts
    // src/modules/serviceaccounts/service-tokens/service-tokens.service.ts
    
    import { User } from '@/modules/users/user.entity';
    import { Injectable } from '@nestjs/common';
    import { ServiceToken } from './service-token.entity';
    import { BaseServiceTokensService } from '@deeepvision/nest-kit/dist/modules/service-accounts';
    
    @Injectable()
    export class ServiceTokensService extends BaseServiceTokensService<User, ServiceToken> {}
  7. Inside the service-accounts/service-tokens folder, create service-accounts.resolver.ts file and extends BaseServiceTokensResolver with the following code:

    ts
    
    // src/modules/serviceaccounts/service-tokens/service-accounts.resolver.ts
    
    import { Resolver } from '@nestjs/graphql';
    import { ServiceToken } from './service-token.entity';
    import { User } from '@/modules/users/user.entity';
    import { BaseServiceTokensResolver } from '@deeepvision/nest-kit/dist/modules/service-accounts';
    
    @Resolver()
    export class ServiceTokensResolver extends BaseServiceTokensResolver<User, ServiceToken>(ServiceToken) {}
  8. Inside the service-accounts folder, create a service-accounts.module.ts file with the following code:

    ts
    // src/modules/service-accounts/service-accounts.module.ts
    
    import { Module } from '@nestjs/common';
    import { ServiceAccountsService } from './service-accounts.service';
    import { ServiceAccountsResolver } from './service-accounts.resolver';
    import { UsersModule } from '../users/users.module';
    import { UserToRolesModule } from '../user-to-roles/user-to-roles.module';
    import { OrganizationsModule } from '../organizations/organizations.module';
    import { ServiceTokensService } from './service-tokens/service-tokens.service';
    import { ServiceTokensResolver } from './service-tokens/service-tokens.resolver';
    import { TypeOrmModule } from '@nestjs/typeorm';
    import { ServiceToken } from './service-tokens/service-token.entity';
    import { SERVICE_ACCOUNTS_SERVICE_TOKEN, SERVICE_TOKENS_SERVICE_TOKEN } from '@deeepvision/nest-kit/dist/modules/service-accounts';
    
    @Module({
      imports: [
        TypeOrmModule.forFeature([
          ServiceToken,
        ]),
        UsersModule,
        UserToRolesModule,
        OrganizationsModule,
      ],
      providers: [
        ServiceAccountsService,
        {
          provide: SERVICE_ACCOUNTS_SERVICE_TOKEN,
          useExisting: ServiceAccountsService,
        },
        ServiceAccountsResolver,
        ServiceTokensService,
        {
          provide: SERVICE_TOKENS_SERVICE_TOKEN,
          useExisting: ServiceTokensService,
        },
        ServiceTokensResolver,
      ],
      exports: [
        ServiceAccountsService,
        {
          provide: SERVICE_ACCOUNTS_SERVICE_TOKEN,
          useExisting: ServiceAccountsService,
        },
      ],
    })
    export class ServiceAccountsModule {}
  9. Finally, import the ServiceAccountsModule into your main AppModule or another module:

    ts
    // src/modules/app.module.ts
    
    import { Module } from '@nestjs/common';
    import { ServiceAccountsModule } from './modules/service-accounts/service-accounts.module.ts';
    
    @Module({
      imports: [ServiceAccountsModule],
    })
    export class AppModule {}

    In this code, we are importing the ServiceAccountsModule and adding it to the imports array of our AppModule.

How to create service account with full access to service

Here's an example of how to call ServiceAccountService.create with an CreateServiceAccountOptions:

ts
const boServiceAccountWithFullAccess = await this.serviceAccountService.create({
  alias: 'backoffice',
  name: 'Backoffice App',
  permissions: [
    'bo:*:*:*',
  ],
});

// boServiceAccountWithFullAccess => User with type "SA"

Each service account is created with a unique email in the format {alias}@{saEmailDomain}. For example, if the alias is backoffice, the email for the service account would be [email protected]. This ensures that each service account has a distinct email address within the system.

Create new service-account with GraphQL (full access)

Here's an example GraphQL mutation to create a new service-account (full access).

How to create service account with specific role in organization

Here's an example of how to call ServiceAccountService.create with an CreateServiceAccountOptions and create service account with role in organization:

ts
const boServiceAccountWithRole = await this.serviceAccountService.create({
  alias: 'backoffice',
  name: 'Backoffice App',
  organizationId: 'hcorg:xjg239iomjs',
  roleId: 'hcrol:2j3g2jgg2jt',
});

// boServiceAccountWithRole => User with type "SA"

Create new service account with GraphQL (with role)

Here's an example GraphQL mutation to create a new service-account (with role).

How to check if service account is exists by alias

To check if a service account with a specific alias exists, you can call the isExists method of the ServiceAccountServices class. Here's an example:

ts
const alias = 'backoffice';
const isExists = await this.serviceAccountService.isExists(alias);

if (isExists) {
  console.log(`A service account with the alias "${alias}" already exists.`);
}

In this example, we check whether a service account with the alias backoffice exists. The isExists method returns a boolean value indicating the existence of the service account.

How to create service token for a service account

To create a long-lived service token for a service account, you can call the createServiceToken method of the ServiceTokensService class. Here's an example:

ts
const input = {
  serviceAccountId: 'hcsa:xxxxxxxxxxx',
  name: 'Token01',
}
const accessToken = await this.serviceTokensService.create(input, ctx);

console.log(`Createed service token for service account ID "${serviceAccountId}": ${accessToken}`);

In this example, we create an serive token for a service account with a given ID. The createServiceToken method returns a string containing the access token. You can then use this token for making authorized requests on behalf of the service account.

Create service token for service account with GraphQL

Here's an example GraphQL mutation to create service token for service account

How to update service account

Here's an example of how to call ServiceAccountService.update with an UpdateServiceAccountOptions and update service account:

ts
const updatedServiceAccount = await this.serviceAccountService.update({
  id: 'hcsa:xxxxxxxxxxx',
  name: 'Updated Backoffice App',
});

How to delete service account

Call the delete method of the ServiceAccountsService and pass in the id of the service account you want to delete:

ts
await this.serviceAccountsService.delete('hcsa:xxxxxxxxxxx');

In this example, we are deleting a service account with an id of hcsa:xxxxxxxxxxx.

Delete service account with GraphQL

Here's an example GraphQL mutation to delete service account.

ServiceAccountsService uses Soft-Delete feature

Soft delete is a feature in NestKit that allows you to mark a record as "deleted" instead of physically deleting it from the database. When you use soft delete, the record is not actually removed from the database, but a status sets to DELETED to indicate that the record has been "soft-deleted". This allows you to retain the data and history associated with the record, while still hiding it from normal queries.

Created by DeepVision Software.