Sign inSign up

cyrius44/verifid

By cyrius44

•Updated 1 day ago

A self-hosted employee identity verification portal powered by Microsoft Entra Verified ID

Image
Security
0

3.4K

cyrius44/verifid repository overview

ā šŸ›”ļø VerifID

VerifID is a contact verification portal based on Microsoft Entra Verified ID.

image

It allows HR teams to provide verifiable credentials to employees. It also provides support teams with a way to verify their identity without a password, using a QR code and Microsoft Authenticator.

The goal is to limit identity theft and fraud.

Microsoft Verified ID provides:

  • Digital fingerprint generation via the "My account" page
  • Digital fingerprint creation and verification APIs

This development offers a user-friendly interface focused on verifying the identity of the person you are interacting with.

Verified ID⁠ For more information, you can visit the Microsoft website.

The development carried out is based on the examples provided by Microsoft in the Azure-Samples repository⁠


⁠Table of Contents


⁠Features

  • 🪪 Credential Issuance — HR issues a VerifiedEmployee verifiable credential directly into the employee's Microsoft Authenticator wallet
  • šŸ” Identity Verification — Helpdesk agents generate a QR code; the employee scans it to prove their identity in seconds
  • šŸ“Ÿ Assistance Code — A short 4-digit code shared verbally with the helpdesk to look up a verification result without needing a session ID
  • šŸ” Azure Entra ID authentication — Optional JWT-based access control with role and scope enforcement (helpdesk, hr)
  • šŸ“± Mobile-first UI — Responsive Angular 21 frontend, installable as a PWA
  • 🐳 Single-container deployment — Frontend and backend bundled in one Docker image
  • šŸ”’ Security headers — CSP, HSTS, X-Frame-Options, Permissions-Policy applied on every response

⁠Screenshot

⁠Identity check (person being checked)
image image image
⁠Identity check (person performing the check)
image image

⁠Architecture

LayerTechnology
FrontendAngular 21 — Signals, Signal Forms, Zoneless, Standalone Components
StylingBootstrap 5.3 + Bootstrap Icons 1.13
BackendFastAPI 0.135 + Python 3.14 (fully async)
ValidationPydantic v2
IdentityMicrosoft Entra Verified ID (Request Service API)
AuthMSAL (frontend) + python-jose JWT validation (backend)
ContainerSingle-stage Docker image — python:3.14-alpine
ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”
│              Docker Container               │
│                                             │
│  ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”   ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā” │
│  │   Angular    │   │      FastAPI        │ │
│  │  (static     │◄──│   /api/v1/...       │ │
│  │   files)     │   │                     │ │
│  ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜   ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¬ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜ │
ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¼ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜
                                │
              ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā–¼ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”
              │  Microsoft Entra Verified ID   │
              │  (verifiedid.did.msidentity.com)│
              ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜

⁠Prerequisites

  • Docker 24+ (or compatible runtime)
  • Docker Compose v2 (optional)
  • A Microsoft Azure tenant with:
    • Microsoft Entra Verified ID enabled and configured
    • Two App Registrations (see Azure App Registrations⁠)
    • A published VerifiedEmployee credential type

⁠Quick Start

⁠Docker CLI
docker run -d \
  --name verifid \
  -p 8080:8080 \
  -e AZURE_TENANT_ID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx \
  -e AZURE_CLIENT_ID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx \
  -e AZURE_CLIENT_SECRET=your-client-secret \
  -e VERIFIED_ID_DID=did:web:yourdomain.com \
  -e VERIFIED_ID_CONTRACT_ID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx \
  -e APP_BASE_URL=https://yourdomain.com \
  -e API_KEY=your-api-key \
  -e AUTH_CLIENT_ID=xxxxxxx-xxx-xxxx-xxxx-xxxxxxxxxxxx \
  ghcr.io/cyr-ius/verifid:latest

Open http://localhost:8000⁠ to access the portal.

⁠Docker Compose
services:
  verifid:
    image: ghcr.io/cyr-ius/verifid:latest
    container_name: verifid
    restart: unless-stopped
    ports:
      - "8080:8080"
    environment:
      - AZURE_TENANT_ID=${AZURE_TENANT_ID}
      - AZURE_CLIENT_ID=${AZURE_CLIENT_ID}
      - AZURE_CLIENT_SECRET=${AZURE_CLIENT_SECRET}
      - VERIFIED_ID_DID=${VERIFIED_ID_DID}
      - VERIFIED_ID_CONTRACT_ID=${VERIFIED_ID_CONTRACT_ID}
      - APP_BASE_URL=${APP_BASE_URL}
      - API_KEY=${API_KEY}
      - AUTH_CLIENT_ID=${AUTH_CLIENT_ID}

Then create a .env file from the provided example:

cp backend/.env.example .env
# Edit .env with your actual values
docker compose up -d

⁠Flows

⁠Verification (Helpdesk)
  1. The helpdesk agent opens /verify and clicks Start verification
  2. VerifID calls the Verified ID Request Service and generates a QR code
  3. A 4-digit assistance code is displayed prominently — the employee communicates it verbally to the agent
  4. The employee scans the QR code with Microsoft Authenticator and confirms credential sharing
  5. The helpdesk UI polls until the credential is verified and displays the employee's claims
  6. Alternatively, the agent can look up the result later via the /assist dashboard using the assistance code
⁠Issuance (HR)
  1. An HR agent opens /issue (requires hr role)
  2. They fill in the employee's details: name, employee ID, job title, department
  3. VerifID generates a QR code — the employee scans it with Microsoft Authenticator
  4. The VerifiedEmployee credential is stored in the employee's wallet, ready to be presented to the helpdesk

⁠Environment Variables

⁠Required
VariableDescription
AZURE_TENANT_IDAzure Active Directory tenant ID
AZURE_CLIENT_IDClient ID of the Backend API app registration (Verif ID API interface)
AZURE_CLIENT_SECRETClient secret for the backend app registration
VERIFIED_ID_DIDYour Verified ID authority DID (e.g. did:web:yourdomain.com)
VERIFIED_ID_CONTRACT_IDCredential contract ID used to build the Verified ID issuance manifest URL
APP_BASE_URLPublic HTTPS base URL of the application — used by Microsoft to POST callbacks
API_KEYShared secret that Microsoft must include in callback headers
AUTH_CLIENT_IDClient ID of the Frontend SPA app registration (Verif ID interface)
⁠Authentication
VariableDescriptionDefault
AUTH_ENABLEDEnable JWT authentication on protected endpointsTrue
AUTH_AUDIENCEComma-separated accepted JWT audiencesAZURE_CLIENT_ID
AUTH_SCOPE Delegated scope accepted for helpdesk accessaccess_as_user
AUTH_JWKS_CACHE_TTL_SECONDSTime to cache JWKS keys (reduce latency)3600
AUTH_ROLE_HELPDESKComma-separated list of valid roleshelpdesk
AUTH_ROLE_HRComma-separated list of valid roleshr
⁠Feature Flags
VariableDescriptionDefault
SWAGGER_ENABLEExpose /api/docs and /api/openapi.jsonFalse
LOG_LEVELLog level (DEBUG, INFO, WARNING, ERROR)INFO
LOGO_URLURL of the logo displayed in the navigation barplaceholder

⁠Azure App Registrations

Two App Registrations are required: one for the Backend API (used by the FastAPI service to call the Verified ID API and validate inbound JWTs), and one for the Frontend SPA (used by the Angular application to authenticate users via MSAL).


⁠App 1 — Backend API App Registration

This registration allows the backend to:

  • Acquire tokens to call the Microsoft Entra Verified ID Request Service
  • Validate JWT access tokens sent by the Angular frontend
  • Expose application roles (helpdesk, hr) and a delegated scope (access_as_user)
⁠Step 1 — Create the registration
  1. Open the Azure portal⁠ and navigate to Microsoft Entra ID → App registrations → New registration
  2. Fill in the form:
    • Name: VerifID – Backend API (or any name you prefer)
    • Supported account types: Accounts in this organizational directory only (Single tenant)
    • Redirect URI: leave empty (the backend does not use redirect flows)
  3. Click Register
  4. Note the Application (client) ID — this is your AZURE_CLIENT_ID
  5. Note the Directory (tenant) ID — this is your AZURE_TENANT_ID
⁠Step 2 — Create a client secret
  1. In the app registration, go to Certificates & secrets → Client secrets → New client secret
  2. Add a description (e.g. verifid-backend) and choose an expiry
  3. Click Add and immediately copy the Value — this is your AZURE_CLIENT_SECRET

āš ļø The secret value is only shown once. Store it securely in a vault or as a Docker secret.

⁠Step 3 — Expose an API (Application ID URI and scope)
  1. Go to Expose an API
  2. Click Set next to Application ID URI — accept the default (api://<client-id>) or use a custom URI
  3. Click Add a scope:
    • Scope name: access_as_user
    • Who can consent: Admins and users
    • Admin consent display name: Access VerifID as a user
    • Admin consent description: Allows the application to access the VerifID helpdesk API on behalf of the signed-in user
    • State: Enabled
  4. Click Add scope
⁠Step 4 — Declare application roles

Application roles are used for server-to-server authorization (helpdesk, hr).

  1. Go to App roles → Create app role

Role 1 — Helpdesk

FieldValue
Display nameHelpdesk
Allowed member typesUsers/Groups
Valuehelpdesk
DescriptionAccess to helpdesk identity verification features
StateEnabled

Role 2 — HR

FieldValue
Display nameHR
Allowed member typesUsers/Groups
Valuehr
DescriptionAccess to HR credential issuance features
StateEnabled
⁠Step 5 — Grant the Verified ID permission

The backend needs to call the Verified ID Request Service using its own identity (client credentials flow).

  1. Go to API permissions → Add a permission → APIs my organization uses
  2. Search for Verifiable Credentials Service Request (App ID: 3db474b9-6a0c-4840-96ac-1fceb342124f)
  3. Select Application permissions → VerifiableCredential.Create.All
  4. Click Add permissions
  5. Click Grant admin consent for <your tenant> — this is required because it is an application permission
⁠Step 6 — Collect the configuration values
.env variableWhere to find it
AZURE_TENANT_IDOverview → Directory (tenant) ID
AZURE_CLIENT_IDOverview → Application (client) ID
AZURE_CLIENT_SECRETCertificates & secrets → the value you copied
AUTH_AUDIENCEapi://<client-id> or the Application ID URI

⁠App 2 — Frontend SPA App Registration

This registration allows the Angular application to sign users in via MSAL and obtain access tokens that are forwarded to the FastAPI backend.

⁠Step 1 — Create the registration
  1. Go to Microsoft Entra ID → App registrations → New registration
  2. Fill in the form:
    • Name: VerifID – Frontend SPA
    • Supported account types: Accounts in this organizational directory only (Single tenant)
    • Redirect URI: Select Single-page application (SPA) and enter https://yourdomain.com (add http://localhost:4200 during development)
  3. Click Register
  4. Note the Application (client) ID — this is your AUTH_CLIENT_ID
⁠Step 2 — Configure authentication
  1. Go to Authentication
  2. Under Single-page application, verify the redirect URI you entered
  3. Add additional redirect URIs if needed (e.g. http://localhost:4200 for local dev)
  4. Under Implicit grant and hybrid flows, make sure both checkboxes are unchecked — MSAL v3/v4 uses the Authorization Code flow with PKCE; implicit grant is not needed and should remain disabled
  5. Under Front-channel logout URL, you can optionally add your logout page URL
  6. Click Save
⁠Step 3 — Add API permissions

The frontend needs permission to call the backend API using the scope created in App 1.

  1. Go to API permissions → Add a permission → My APIs
  2. Select VerifID – Backend API
  3. Select Delegated permissions → access_as_user
  4. Click Add permissions
  5. Click Grant admin consent for <your tenant> (optional but recommended to avoid per-user consent prompts)
⁠Step 4 — Assign users to roles

Roles are assigned via Enterprise Applications, not App Registrations.

  1. Navigate to Microsoft Entra ID → Enterprise Applications
  2. Search for VerifID – Backend API (the enterprise app is automatically created alongside the app registration)
  3. Go to Users and groups → Add user/group
  4. Select the users or groups you want to assign and pick the role (Helpdesk or HR)
  5. Click Assign

Role assignments are reflected in the roles claim of the access token. Users without an assigned role will receive a 403 on protected endpoints.

⁠Step 5 — Collect the configuration values
.env variableWhere to find it
AUTH_CLIENT_IDOverview → Application (client) ID of the SPA registration

⁠Summary Table
PurposeApp RegistrationKey values
Backend token acquisition & JWT validationVerifID – Backend APIAZURE_CLIENT_ID, AZURE_CLIENT_SECRET, AUTH_AUDIENCE
Frontend user sign-in (MSAL)VerifID – Frontend SPAAUTH_CLIENT_ID

⁠Roles & Permissions

Role / ScopeGrants access to
helpdesk (app role)/api/v1/verified-id/assist/{code}
hr (app role)/api/v1/verified-id/issue
(no auth)/verify page and /api/v1/verified-id/verify

Authentication can be disabled entirely by setting AUTH_ENABLED=False — useful during initial setup and testing.


⁠Development

⁠Prerequisites
  • Python 3.14+
  • Node.js 18+
  • Angular CLI 21

A ready-to-use VS Code Dev Container is included (.devcontainer/). Open the repository in VS Code and select Reopen in Container to get a fully configured environment with Python, Node, Angular CLI, and all dependencies installed automatically.

⁠Backend
cd backend
cp .env.example .env   # fill in your Azure values
uv sync
uvicorn app.main:app --reload --host 0.0.0.0 --port 8000

API docs are available at http://localhost:8000/api/docs when SWAGGER_ENABLE=True.

⁠Frontend
cd frontend
npm install
ng serve --host 0.0.0.0   # proxies /api/* to http://localhost:8000

The Angular dev server starts at http://localhost:4200.

⁠Build & Run (local Docker)
docker compose up --build

⁠CI / CD

A GitHub Actions workflow can be added to build and publish the Docker image automatically on every push to main and on version tags. The recommended tag strategy is latest, X.Y.Z, and sha-<commit>.


⁠Healthcheck

GET /api/health returns:

{ "status": "healthy", "service": "VerifID API" }

⁠License

MIT — see LICENSE⁠ for details.

Author: @cyr-ius⁠

Tag summary

Content type

Image

Digest

sha256:c934647d8…

Size

78.7 MB

Last updated

1 day ago

docker pull cyrius44/verifid