Connection with managed identity to postgresql and token expiration

Vasile 0 Reputation points
2025-01-22T10:35:50.8366667+00:00

Hello community, I have a Nest.Js app with TypeORM and PostgreSQL.I want to deploy my app to the azure and to connect the azure PostgreSQL database.I implemented next connection:

Database module:

import { Module } from '@nestjs/common';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { TypeOrmModule } from '@nestjs/typeorm';
import { join } from 'path';
import { NODE_ENV } from 'src/common/enums/node.env.enum';
import { IPostgresConfig } from 'src/common/interfaces/postgres.config.interface';
import { getManagedIdentityCredential } from 'src/common/managed-identity/credential';
import { getDatabaseAccessToken } from 'src/common/managed-identity/database.access.token';
import { DataSource } from 'typeorm';
@Module({
  imports: [
    TypeOrmModule.forRootAsync({
      imports: [ConfigModule],
      inject: [ConfigService],
      useFactory: async (configService: ConfigService) => {
        const databaseConfig =
          configService.get<IPostgresConfig>('postgresConfig');
        const managedIdentityConfig = configService.get('managedIdentity');
        const env = configService.get<string>('NODE_ENV');
        const isTestEnv = env === NODE_ENV.TEST;
        const _logging =
          env !== NODE_ENV.LOCAL &&
          env !== NODE_ENV.DEVELOPMENT &&
          env !== NODE_ENV.TEST;
        const _synchronize =
          env === NODE_ENV.LOCAL ||
          env === NODE_ENV.DEVELOPMENT ||
          env === NODE_ENV.TEST;
        const useSsl =
          env === NODE_ENV.DEVELOPMENT ||
          env === NODE_ENV.TEST ||
          env === NODE_ENV.PRODUCTION;
        const useManagedIdentity =
          env === NODE_ENV.DEVELOPMENT ||
          env === NODE_ENV.TEST ||
          env === NODE_ENV.PRODUCTION;
        let password: string;
        if (useManagedIdentity) {
          const credential = getManagedIdentityCredential(
            managedIdentityConfig,
          );
          const accessToken = await getDatabaseAccessToken(credential);
          password = accessToken.token;
        } else {
          password = databaseConfig.password;
        }
        return {
          type: 'postgres',
          host: databaseConfig.host,
          database: isTestEnv ? 'test_db' : databaseConfig.database,
          schema: databaseConfig.schema,
          username: databaseConfig.user,
          password,
          port: +databaseConfig.port,
          ssl: useSsl || { rejectUnauthorized: false },
          entities: [
            join(
              __dirname,
              '..',
              '..',
              'modules',
              '**',
              'entities',
              '*.entity.{ts,js}',
            ),
            join(
              __dirname,
              '..',
              '..',
              'common',
              'entities',
              '*.entity.{ts,js}',
            ),
            join(__dirname, '..', '**', 'entities', '*.entity.{ts,js}'),
          ],
          migrations: [join(__dirname, 'migrations', '*.{ts,js}')],
          synchronize: _synchronize,
          logging: _logging,
          dropSchema: isTestEnv,
        };
      },
      dataSourceFactory: async (options) => {
        const dataSource = await new DataSource(options).initialize();
        return dataSource;
      },
    }),
  ],
})
export class DatabaseModule {}

Credentials.ts

import { DefaultAzureCredential } from '@azure/identity';
type ManagedIdentityConfig = {
  clientId: string;
};
export function getManagedIdentityCredential({
  clientId,
}: ManagedIdentityConfig) {
  const credential = new DefaultAzureCredential({
    managedIdentityClientId: clientId,
  });
  return credential;
}

And database.access.token.ts

import { AccessToken, DefaultAzureCredential } from '@azure/identity';
const databaseScope = 'https://ossrdbms-aad.database.windows.net/.default';
export const getDatabaseAccessToken = async (
  credential: DefaultAzureCredential,
): Promise<AccessToken> => {
  const tokenResponse = await credential.getToken(databaseScope);
  return tokenResponse;
};

The problem is that access token expires and the db connection get lost.And i get this error:

User's image

Maybe i do something wrong about managed identity?I have asked on Nestjs and TypeORM platforms but no answer.Thanks a lot already :)

Microsoft Identity Manager
Microsoft Identity Manager
A family of Microsoft products that manage a user's digital identity using identity synchronization, certificate management, and user provisioning.
743 questions
Azure Database for PostgreSQL
{count} votes

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.