Repository: logto-io/logto
File: packages/core/src/routes/interaction/consent/index.ts (TypeScript)

Code before:
    }),
    async (ctx, next) => {
      const { interactionDetails } = ctx;

      const {
        session,
        params: { client_id: clientId, redirect_uri: redirectUri },
        prompt,
      } = interactionDetails;

      assertThat(session, 'session.not_found');

      assertThat(
        clientId && typeof clientId === 'string',
        new InvalidClient('client must be available')
      );

      assertThat(
        redirectUri && typeof redirectUri === 'string',
        new InvalidRedirectUri('redirect_uri must be available')
      );

      const { accountId } = session;

      const application =
        buildBuiltInApplicationDataForTenant('', clientId) ??
        (await queries.applications.findApplicationById(clientId));

      const applicationSignInExperience =
        await queries.applicationSignInExperiences.safeFindSignInExperienceByApplicationId(
          clientId
        );

      const userInfo = await queries.users.findUserById(accountId);

      const { missingOIDCScope, missingResourceScopes: allMissingResourceScopes = {} } =
        getMissingScopes(prompt);

      // The missingResourceScopes from the prompt details are from `getResourceServerInfo`,
      // which contains resource scopes and organization resource scopes.
      // We need to separate the organization resource scopes from the resource scopes.
      // The "scopes" in `missingResourceScopes` do not have "id", so we have to rebuild the scopes list.
      const missingResourceScopes = await filterAndParseMissingResourceScopes({
        resourceScopes: allMissingResourceScopes,
        queries,
        libraries,
        userId: accountId,
        applicationId: clientId,
      });

      // Find the organizations if the application is requesting the organizations scope

Review comment (suggestion):
ditto: From the method name `buildBuiltInApplicationDataForTenant`, it should only take the built-in application's `clientId`.  Maybe a util method `isBuiltInClientId`  and a literal type `BuiltInClientIds`

Code after:
      response: consentInfoResponseGuard,
    }),
    async (ctx, next) => {
      const { interactionDetails } = ctx;

      const {
        session,
        params: { client_id: clientId, redirect_uri: redirectUri },
        prompt,
      } = interactionDetails;

      assertThat(session, 'session.not_found');

      assertThat(
        clientId && typeof clientId === 'string',
        new InvalidClient('client must be available')
      );

      assertThat(
        redirectUri && typeof redirectUri === 'string',
        new InvalidRedirectUri('redirect_uri must be available')
      );

      const { accountId } = session;

      const application = isBuiltInApplicationId(clientId)
        ? buildBuiltInApplicationDataForTenant('', clientId)
        : await queries.applications.findApplicationById(clientId);

      const applicationSignInExperience =
        await queries.applicationSignInExperiences.safeFindSignInExperienceByApplicationId(
          clientId
        );

      const userInfo = await queries.users.findUserById(accountId);

      const { missingOIDCScope, missingResourceScopes: allMissingResourceScopes = {} } =
        getMissingScopes(prompt);

      // The missingResourceScopes from the prompt details are from `getResourceServerInfo`,
      // which contains resource scopes and organization resource scopes.
      // We need to separate the organization resource scopes from the resource scopes.
      // The "scopes" in `missingResourceScopes` do not have "id", so we have to rebuild the scopes list.
      const missingResourceScopes = await filterAndParseMissingResourceScopes({
        resourceScopes: allMissingResourceScopes,
        queries,
        libraries,
        userId: accountId,
        applicationId: clientId,
      });