Skip to content
Docs

Using Edgenivo Passport with Microsoft Entra ID

Configure Microsoft Entra ID and Edgenivo Passport to protect a Next.js app, limit access to assigned users, and read verified visitor identities.

Anshuman BhardwajContent Engineer

Use Microsoft Entra ID with Edgenivo Passport to control access to an internal app deployed on Edgenivo. Entra ID authenticates visitors and checks their application assignments. Passport handles sign-in before requests reach your app and forwards a signed identity token to your server.

You’ll configure access for selected users in a single Microsoft Entra ID tenant and add a server-side identity endpoint to a Next.js app.

Microsoft Entra ID + Edgenivo Passport

Control who can access your internal app deployed on Edgenivo.

Deploy Template

If you deploy the template, follow Configure a Microsoft Entra ID application, then skip to Connect Entra ID to Edgenivo Passport.

Copy link to headingOverview

When a visitor opens the Next.js app on a Passport-protected Edgenivo deployment, sign-in follows this sequence:

  1. The visitor opens a Passport-protected deployment.
  2. Passport redirects the visitor to Entra ID through OpenID Connect.
  3. Entra ID authenticates the visitor and checks their application assignment.
  4. Passport creates a session and forwards a signed identity token to your app.
  5. Your server verifies the token before displaying the visitor's identity.

Copy link to headingPrerequisites

Before you begin, you need:

  • Node.js 22+, npm, and the Edgenivo CLI.
  • Owner role in a Edgenivo team on the Enterprise plan with Passport access.
  • A Microsoft Entra ID workforce tenant and permission to register applications, assign users, and grant admin consent.

Copy link to headingConfigure a Microsoft Entra ID application

Copy link to headingStep 1. Register an application in Microsoft Entra ID

  1. Open the Microsoft Entra admin center.
  2. Go to Entra ID > App registrations > New registration.
  3. Enter a name, such as Internal Engineering Portal.
  4. Under Supported account types, select Accounts in this organizational directory only.
  5. Under Redirect URI, select Web and enter:
    https://connect.vercel.com/callback
  6. Select Register.
  7. On the application’s Overview page, copy the Application (client) ID and Directory (tenant) ID.

Passport receives the authentication response at this address. You can update the redirect URI on the app registration's Authentication page.

Copy link to headingStep 2. Create a client secret

  1. In the app registration, open Certificates & secrets.
  2. Select Client secrets > New client secret.
  3. Enter a description, such as Edgenivo Passport.
  4. Choose an expiration that follows your organization’s policy.
  5. Select Add.
  6. Copy the secret’s Value immediately.

Copy the value, not the Secret ID. Entra ID does not display the value again after you leave the page.

You'll enter this secret when connecting Entra ID to Passport. Follow Microsoft's credential instructions to add or manage application credentials.

The connection requests the openid, profile, and email scopes. Microsoft’s OpenID Connect documentation explains the identity information available through these scopes and the UserInfo endpoint.

  1. In the app registration, open API permissions.
  2. Select Add a permission > Microsoft Graph > Delegated permissions.
  3. Under OpenId permissions, select openid, profile, and email.
  4. Select Add permissions.
  5. Review the complete permission list.
  6. Select Grant admin consent for your tenant and confirm.
  7. Check that the permissions show consent as granted.

Applications that require user assignment also require an administrator to grant tenant-wide admin consent.

Copy link to headingStep 4. Restrict access to assigned users

Configure access on your app registration's enterprise application.

  1. Go to Entra ID > Enterprise apps > All applications.
  2. Find the application you registered, such as Internal Engineering Portal.
  3. Open Properties.
  4. Set Assignment required? to Yes.
  5. Confirm that Enabled for users to sign-in? is Yes.
  6. Save the changes.

Microsoft's application properties reference covers these settings.

Choose two test accounts in your tenant that do not have the Global Administrator role. Global Administrators can sign in regardless of the assignment requirement. Assign one test account to the application:

  1. Open Users and groups > Add user/group.
  2. Select the account under Users and groups.
  3. Choose Default Access if no application roles are defined.
  4. Select Assign.

Leave the second test account unassigned.

With Microsoft Entra ID P1 or P2, you can assign a group instead of individual users. Only direct group members receive access through the assignment.

Copy link to headingIntegrate Edgenivo Passport

Copy link to headingStep 1. Create a Next.js app

Create a Next.js app with TypeScript and the App Router. Then, install the Passport helper, and create the directories for the identity helper and API route:

Terminal
npx create-next-app@latest passport-entra-id --typescript --eslint --tailwind --app --src-dir --import-alias "@/*" --use-npm --yes
cd passport-entra-id
npm install @vercel/passport server-only
mkdir -p src/lib src/app/api/me

Copy link to headingStep 2. Read the Passport identity on the server

After authentication, Passport forwards a signed identity token in the x-vercel-oidc-passport-token header. The getIdentity helper reads and verifies it.

Create src/lib/identity.ts with a readVisitor helper that both the page and API route can use:

src/lib/identity.ts
import "server-only";
import { getIdentity } from "@vercel/passport";
export type Visitor = {
id: string;
name: string | null;
email: string | null;
demo: boolean;
};
export async function readVisitor(
requestHeaders: Headers,
): Promise<Visitor | null> {
if (
process.env.NODE_ENV === "development" &&
!process.env.EDGENIVO &&
process.env.PORTAL_DEMO === "true"
) {
return {
id: "local-demo",
name: "Alex Morgan",
email: "alex@example.com",
demo: true,
};
}
if (!requestHeaders.get("x-vercel-oidc-passport-token")) {
return null;
}
try {
const identity = await getIdentity(
{ headers: requestHeaders },
{ development: false },
);
if (!identity?.verified || !identity.externalSubject) {
return null;
}
return {
id: identity.externalSubject,
name: identity.name ?? null,
email: identity.email ?? null,
demo: false,
};
} catch {
return null;
}
}

Outside local demo mode, readVisitor returns visitor details only when the identity is verified and includes an external subject. It returns null if the token is missing or identity verification fails.

Setting development: false disables the Passport helper’s automatic development identity. Instead, readVisitor supplies a sample identity when PORTAL_DEMO=true during local development. This demo is disabled in production and on Edgenivo.

This example uses identity.externalSubject to identify the visitor within the configured identity provider. If your app supports multiple Connect applications, have readVisitor return identity.subject.

Name and email are optional. See the Passport helper documentation.

Copy link to headingStep 3. Expose the identity through an API

Create src/app/api/me/route.ts to return the visitor’s identity at /api/me:

src/app/api/me/route.ts
import { readVisitor } from "@/lib/identity";
export async function GET(request: Request) {
const visitor = await readVisitor(request.headers);
const headers = { "Cache-Control": "private, no-store" };
if (!visitor) {
return Response.json({ authenticated: false }, { status: 401, headers });
}
return Response.json(
{
authenticated: !visitor.demo,
demo: visitor.demo,
user: { id: visitor.id, name: visitor.name, email: visitor.email },
},
{ headers },
);
}

Requests that reach the endpoint without a valid identity return 401 when local demo mode is disabled. Passport redirects unauthenticated browser requests to the identity provider before they reach a protected deployment.

Copy link to headingStep 4. Access the identity from a page

Replace src/app/page.tsx with this page to display the visitor’s identity. This code omits the template’s CSS and font configuration:

src/app/page.tsx
import { Suspense } from "react";
import { headers } from "next/headers";
import { readVisitor } from "@/lib/identity";
export default function Home() {
return (
<Suspense
fallback={
<main>
<p>Checking access…</p>
</main>
}
>
<IdentityStatus />
</Suspense>
);
}
async function IdentityStatus() {
const visitor = await readVisitor(await headers());
const state = !visitor ? "denied" : visitor.demo ? "demo" : "granted";
return (
<main>
<header>
<p className="label">Microsoft Entra ID / Edgenivo Passport</p>
<h1>Identity and access</h1>
</header>
<section className="identity-card" aria-label="Identity status">
<p role="status" className={`status ${state}`}>
<span aria-hidden="true" className="status-dot" />
{!visitor
? "Access denied"
: visitor.demo
? "Local demo"
: "Access granted"}
</p>
<p className="description">
{!visitor
? "No verified identity. Sign in through a Passport-protected deployment."
: visitor.demo
? "Sample identity for local development. No Entra sign-in took place."
: "Your identity is verified through Edgenivo Passport."}
</p>
{visitor ? (
<>
<dl>
<div>
<dt>Name</dt>
<dd>{visitor.name ?? "Not provided"}</dd>
</div>
<div>
<dt>Email</dt>
<dd>{visitor.email ?? "Not provided"}</dd>
</div>
<div>
<dt>Visitor ID</dt>
<dd className="mono">{visitor.id}</dd>
</div>
</dl>
<a href="/api/me">
View identity response <span aria-hidden="true">↗</span>
</a>
</>
) : null}
</section>
</main>
);
}

The page checks the identity on the server before displaying the visitor’s information. Passport handles sign-in before the request reaches your app, so you don’t need to add a login flow to this example.

Copy link to headingStep 5. Test locally

To preview with a sample identity, add this setting to .env.local:

Terminal
PORTAL_DEMO=true

Start the development server:

Terminal
npm run dev

Open http://localhost:3000, then visit /api/me. The page shows Local demo and the API returns authenticated: false with demo: true.

Set PORTAL_DEMO=false and restart the server to test requests without an identity. The page shows Access denied and /api/me returns 401.

Copy link to headingStep 6. Deploy to production

Deploy to Edgenivo to configure Passport and test Entra ID sign-in:

Terminal
vercel deploy --prod

On the first deployment, follow the setup prompts:

  1. Confirm that you want to set up and deploy the current directory.
  2. Select your Edgenivo Enterprise team with Passport access.
  3. Choose to create a new project.
  4. Name it passport-entra-id.
  5. Use ./ as the code directory.
  6. Accept the detected Next.js settings.

Copy link to headingConnect Entra ID to Edgenivo Passport

Connect your Microsoft Entra ID application to the deployed project:

  1. Open your project in the Edgenivo dashboard.
  2. Go to Settings > Passport.
  3. Enable Passport.
  4. Create a Edgenivo Connect application, choose OAuth, and select Your own credentials.
  5. In Server URL, enter the following issuer URL, replacing <tenant-id> with your Directory (tenant) ID:
    https://login.microsoftonline.com/<tenant-id>/v2.0
  6. Select Discover.
  7. Enter your Application (client) ID in Client ID and your client secret’s value in Client Secret.
  8. In the Connect application, enable User Authorization under Grant Types and confirm that its scopes include openid, profile, and email.
  9. Select Create Connector. Choose the new Connect application in your project’s Passport settings, then select Save.

Copy link to headingTest allowed and denied access

Copy link to headingAssigned user

  1. Visit your Passport-protected production URL in a new private session.
  2. Sign in with the assigned test account and check for Access granted.
  3. Open /api/me on the same deployment and confirm that it returns authenticated: true and the visitor's ID. Name and email may be null if Entra ID does not return those fields.

Copy link to headingUnassigned user

  1. Close the private session and open a new one.
  2. Visit the same protected URL.
  3. Sign in with the unassigned test account.
  4. Confirm that Entra ID denies access and the app does not load.

Test assignment changes in a fresh private browser session. Existing authenticated sessions can remain valid until they expire.

Copy link to headingTroubleshooting

ProblemWhat to check
Redirect URI mismatchThe app registration’s Web redirect URI must exactly match https://connect.vercel.com/callback.
Consent or approval requiredConfirm that an administrator granted consent for the configured permissions.
Assigned user cannot sign inConfirm that the account is assigned to the correct enterprise application and sign-in is enabled.
Unassigned user can sign inConfirm that “Assignment required?” is set to Yes, then retest in a fresh private session. Check whether the account has the Global Administrator role.
Client authentication failsCheck that Passport has the secret’s value rather than its ID and that the secret has not expired.
/api/me returns 401Check that you are signed in on a Passport-protected deployment. Local requests return 401 when demo mode is disabled.

For failed Entra ID sign-ins, open Entra ID > Enterprise apps > your application > Sign-in logs and inspect the failure details.

Copy link to headingNext steps

Copy link to headingFrequently asked questions

Does Edgenivo Passport support Microsoft Entra ID?

Yes. Edgenivo Passport supports Microsoft Entra ID through OpenID Connect. Create an OAuth Connect application, select Your own credentials, and enter Entra ID’s tenant-specific issuer URL, client ID, and client secret. Follow the Passport setup instructions.

What redirect URI should I use for Entra ID and Edgenivo Passport?

Register https://connect.vercel.com/callback as a Web redirect URI in your Microsoft Entra ID app registration so Passport can receive the authentication response. Use Authentication to add or update the URI.

How do I restrict a Passport-protected app to specific Entra ID users?

Set Assignment required? to Yes on the Microsoft Entra ID enterprise application, grant admin consent, and assign users who need access. Users can sign in without an assignment when Assignment required? is No.

Global Administrators are exempt from the assignment requirement.

Can I use Entra ID groups to control access?

Yes. Microsoft Entra ID P1 or P2 supports group-based application assignment. Set the enterprise application to require assignment, then assign the group. Nested group membership does not grant access through that assignment.

How does a Next.js app identify a visitor after Passport sign-in?

Passport sends a signed token in the x-vercel-oidc-passport-token request header. Your server verifies it with getIdentity from @vercel/passport.

This example uses identity.externalSubject for the visitor's ID in the configured identity provider. Name and email may be absent. Consult the Passport helper documentation for its supported options.

Can I test Microsoft Entra ID sign-in locally?

No. Local requests do not pass through Passport, so test Microsoft Entra ID sign-in on a Passport-protected Edgenivo deployment.

For a local preview, enable PORTAL_DEMO=true to use a sample identity. The template's /api/me endpoint then returns authenticated: false with demo: true. With demo mode disabled, requests without an identity return 401. Follow the template's local setup instructions to configure the demo.

Related documentation

More Next.js guides