Integrations

Microsoft Azure (Graph API)

This module allows Anjana Data to connect to your Microsoft Azure tenant (Entra ID) to download and synchronize users.

There are two synchronization modes depending on whether service-principal-id is configured or not:

  • Enterprise Application filtered mode (with service-principal-id): Anjana queries the Microsoft Graph API to obtain only the users and groups assigned to that application in Azure. Recommended when only a subset of tenant users should have access.

  • Full tenant mode (without service-principal-id): Anjana synchronizes all users in the Azure AD tenant. Useful when all directory users should have access.


Part 1: Configuration in Azure Portal

To configure provisioning, we need an App Registration (for API credentials) and, optionally, an Enterprise Application (if you want to filter users by application).

Step 1: Create the App Registration (API Credentials)

  1. Go to Microsoft Entra ID > App registrations.

  2. Click New registration.

  3. Give it a name (e.g. Anjana Data Provisioning) and click Register.

  4. Obtain Credentials:

    • In "Overview", copy the Directory (tenant) ID (tenant-id).

    • Copy the Application (client) ID (client-id).

  5. Create Secret:

    • Go to Certificates & secrets > New client secret.

    • Add a description and an expiration.

    • Copy the secret's Value (Important! Copy the value, not the ID). This will be your client-secret.

Step 2: Assign API Permissions

For Anjana to be able to read users, the registration created needs permissions on Microsoft Graph.

  1. In the App Registration menu, go to API permissions.

  2. Click + Add a permission > Microsoft Graph > Application permissions (NOT delegated permissions).

  3. Search for and check the following permissions:

    • User.Read.All (To read user profiles).

    • GroupMember.Read.All (To read group members if using group-based assignment).

    • Application.Read.All (To read the application configuration).

    • AppRoleAssignment.ReadWrite.All (To read who is assigned to the app; only necessary in application-filtered mode).

  4. Click Add permissions.

  5. CRUCIAL: Click "Grant admin consent for..." and confirm with "Yes". The permissions should show a green checkmark in the status column.

Step 3: Obtain the Service Principal ID (Optional - only for application-filtered mode)

This step is only necessary if you want to restrict synchronization to users assigned to a specific Enterprise Application. If you omit service-principal-id, Anjana will synchronize all tenant users.

  1. Go to the main Microsoft Entra ID menu > Enterprise Applications.

  2. Search for the application created in Step 1 (you can search by name or by Client ID).

  3. Click on the application to open it.

  4. Go to Properties in the side menu.

  5. Copy the Object ID. This value is the service-principal-id.

    • Note: Make sure this ID is different from the "Application (client) ID".


Part 2: Configuration in application.yml

Edit Anjana's configuration file and include the data obtained in the security.provisioning.providers.azure-graph section.

Enterprise Application filtered mode (with service-principal-id)

Only the users assigned to the specified application are synchronized (directly or through groups).

YAML
security:
  provisioning:
    providers:
      azure-graph:
        azure-prod:
          tenant-id: "88888888-4444-4444-4444-121212121212"
          client-id: "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"
          client-secret: "XyZ123..."
          # Object ID of the ENTERPRISE APPLICATION (Step 3)
          service-principal-id: "99999999-5555-5555-5555-333333333333"

Full tenant mode (without service-principal-id)

All users in the Azure AD tenant are synchronized.

YAML
security:
  provisioning:
    providers:
      azure-graph:
        azure-prod:
          tenant-id: "88888888-4444-4444-4444-121212121212"
          client-id: "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"
          client-secret: "XyZ123..."
          # service-principal-id not configured -> synchronization of the entire tenant

Summary of Required Data

YAML Property

Name in Azure Portal

Where to find it

Required

tenant-id

Directory (tenant) ID

App Registration > Overview

Yes

client-id

Application (client) ID

App Registration > Overview

Yes

client-secret

Secret value

App Registration > Certificates & secrets

Yes

service-principal-id

Object ID

Enterprise Applications > Properties

No (optional)

When service-principal-id is absent or empty, Anjana uses Microsoft Graph's GET /users API with OData pagination to obtain all tenant users. When present, it uses GET /servicePrincipals/{id}/appRoleAssignedTo to obtain only the users and groups assigned to that application, expanding groups transitively.


Custom field mapping (field-mapping)

Anjana includes a default mapping that covers the usual cases. You can override any field by specifying the provider key from which the value should be read. Keys are listed in priority order: the first non-empty value is used.

Default mapping

Anjana field

Default keys (priority order)

userName

userPrincipalName

email

mail, otherMails

firstName

givenName

lastName

surname

phone

mobilePhone

title

jobTitle

Available fields

Key

Description

id

Unique identifier of the object in Azure AD.

userPrincipalName

User's UPN (e.g. user@company.com).

displayName

Display name.

mail

Primary email address.

otherMails

List of additional email addresses.

givenName

First name.

surname

Last name.

mobilePhone

Mobile phone.

businessPhones

List of business phone numbers.

jobTitle

Job title.

department

Department.

officeLocation

Office location.

companyName

Company name.

employeeId

Employee identifier.

preferredLanguage

Preferred language (e.g. es-ES).

Configuration example

YAML
security:
  provisioning:
    providers:
      azure-graph:
        azure-prod:
          tenant-id: "..."
          client-id: "..."
          client-secret: "..."
          field-mapping:
            # Use mail instead of userPrincipalName as login
            user-name: ["mail"]
            # Business phone with fallback to mobile
            phone: ["businessPhones", "mobilePhone"]
            # Job title; if empty, use the department
            title: ["jobTitle", "department"]