> For the complete documentation index, see [llms.txt](https://docs.licensemeter.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.licensemeter.com/self-hosting/microsoft-setup.md).

# Microsoft application setup

Configure the application registrations used by your own LicenseMeter deployment.

This guide is for operators of a self-hosted installation. Hosted LicenseMeter users should start with the [Microsoft connector](/connectors/microsoft.md).

For Docker, start with [Self-hosting with Docker](/self-hosting.md). This reference also covers Vercel and other Node.js hosts.

## Authentication

The Microsoft connector is separate from sign-in.

| Provider        | Configuration                                                                                                                                   |
| --------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
| Microsoft Entra | `AUTH_PROVIDER=entra`, `AUTH_MICROSOFT_ENTRA_ID_ID`, `AUTH_MICROSOFT_ENTRA_ID_SECRET`                                                           |
| WorkOS AuthKit  | `AUTH_PROVIDER=workos` (application default), `WORKOS_API_KEY`, `WORKOS_CLIENT_ID`, `WORKOS_COOKIE_PASSWORD`, `NEXT_PUBLIC_WORKOS_REDIRECT_URI` |

Compose selects Entra and needs no WorkOS account. A sample instance runs without provider credentials when `AUTH_PROVIDER=entra` and `DEMO_MODE=true`.

For WorkOS, register your deployment's `/auth/callback` URL and `/auth/sign-in` endpoint. The cookie password must contain at least 32 characters. Configure `NEXT_PUBLIC_WORKOS_REDIRECT_URI` before building. Follow the [AuthKit Next.js documentation](https://workos.com/docs/authkit/nextjs).

## Microsoft registrations

[setup-entra.ps1](https://github.com/ugurkocde/licensemeter-website/blob/main/scripts/setup-entra.ps1) creates separate sign-in and read-only connector applications in the tenant you select. Review the script and its requested permissions before running it. It creates application registrations and credentials in the selected Microsoft tenant, affecting sign-in and connector access for this deployment. Start in a test tenant, verify the tenant and generated applications, and stop if the requested permissions or redirect URLs differ from your plan. To retire the setup, revoke consent, remove the created credentials and applications, and remove their deployment settings. This stops sign-in or refresh for the installation; it does not erase data already collected.

```powershell
Install-Module Microsoft.Graph.Applications -Scope CurrentUser
./scripts/setup-entra.ps1 -BaseUrl "https://licenses.example.com"
```

Register these Web redirect URIs for your deployment:

* Sign-in: `https://licenses.example.com/api/auth/callback/microsoft-entra-id`
* Connector: `https://licenses.example.com/api/connect/callback`

Store the generated IDs and secrets in deployment environment variables. The connector uses `CONNECTOR_CLIENT_ID` and `CONNECTOR_CLIENT_SECRET`, independently of the login provider. Its setup page also supports bringing your own app registration. `scripts/add-redirect-uris.ps1` requires your own sign-in and connector app IDs explicitly.

The managed connector requests `User.Read.All`, `AuditLog.Read.All`, `Reports.Read.All`, `LicenseAssignment.Read.All`, and `ReportSettings.Read.All`. Consent and publisher requirements depend on the target tenant's policies. See Microsoft's [admin-consent documentation](https://learn.microsoft.com/entra/identity-platform/v2-admin-consent) and [publisher verification overview](https://learn.microsoft.com/entra/identity-platform/publisher-verification-overview).

## Shared environment

| Variable                                                     | Purpose                                                                     |
| ------------------------------------------------------------ | --------------------------------------------------------------------------- |
| `DATABASE_URL`                                               | PostgreSQL connection using the limited runtime role                        |
| `AUTH_SECRET`                                                | Session signing secret, at least 32 characters in production                |
| `DATA_ENCRYPTION_KEY`                                        | Separate encryption key for connector credentials                           |
| `APP_BASE_URL`                                               | Canonical deployment origin, HTTPS for public access                        |
| `CRON_SECRET`                                                | Bearer secret for scheduled-job routes                                      |
| `DEMO_MODE`                                                  | `true` enables credentials-free sample-workspace access                     |
| `SELF_HOSTED`                                                | `true` enables runtime page configuration and disables hosted chat defaults |
| `RESEND_API_KEY`, `EMAIL_FROM`                               | Optional transactional email                                                |
| `SUPPORT_TO_EMAIL`                                           | Destination for the self-hosted support form                                |
| `SUPPORT_TURNSTILE_SITE_KEY`, `SUPPORT_TURNSTILE_SECRET_KEY` | Optional spam verification; configure both for your hostname                |
| `CRISP_WEBSITE_ID`                                           | Optional chat website ID for your instance                                  |

Never commit environment files, database dumps, or private keys. `SKIP_ENV_VALIDATION` is for builds without secrets, not runtime deployment.

## Database and hosting

Docker initializes its dedicated database automatically. Do not point its initial migration at an existing hosted database; it creates a complete schema and requires an empty database.

For an independently managed PostgreSQL database, provision the schema as the database owner and use a separate login for runtime. Keep administrator connection strings out of the web environment.

The `scripts/db-*.sql` files describe the hosted Supabase deployment: RLS, application-role DML permissions, and denial of Supabase Data API access. Tenant isolation remains in application code. Review these files before applying them, and run `scripts/db-audit-posture.sql` after schema changes. The bundled PostgreSQL service has no Data API and does not need these Supabase-specific scripts.

For Vercel, configure the database, authentication, encryption, `APP_BASE_URL`, and `CRON_SECRET`. `vercel.json` schedules the sync, digest, and monthly report. The hosted deployment retains its WorkOS and Crisp behavior; `SELF_HOSTED=true` is for instances you operate yourself.

## First connection

Sign in, open Connectors, and select Microsoft 365. Review the read-only permissions and complete consent with an account permitted to grant it. After syncing, review findings and set the license price book to your agreements. Invite colleagues through workspace membership controls.

Some activity signals require additional Microsoft licensing or identifiable reports. The application exposes missing signals and falls back where supported. It does not change report privacy settings on your behalf.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.licensemeter.com/self-hosting/microsoft-setup.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
