Skip to content

Read-Model Query Testing

This document provides examples for testing the read-model endpoint (POST /api/readmodel) and its authentication behaviour. Requests are intended to be run with Bruno; each example shows the request followed immediately by its expected response.

In the responses below, requestTime and claim identifiers vary per request, and roles / name / email reflect whichever account you authenticate as. The examples use the seeded system and admin dev accounts.

Prerequisites

  1. Install Bruno.
  2. Run the application from Visual Studio: set LBS.AspireHost as the startup project and start it. When the Aspire session launches and the site appears, copy the generated URL — this is your base URL (referred to as <base-url> below). Use it as the root for every Bruno request.
  3. Configure authentication (see below).

Authentication Setup

Some queries are public and some require authentication. For authenticated requests, use a seeded service account with Basic Auth.

Do not hardcode credentials in this document or commit them. Request the service account username and password from your team lead / Engineering Lead. In Bruno, store them as secret environment variables and reference those variables from the request's Basic Auth fields, so the values never end up in committed files. For the admin role-hierarchy test below, request an admin service account. Bruno builds the Basic Auth header for you — there is no need to base64-encode anything by hand.

Test Authentication Queries

1. AuthTest Query (Public — No Authentication Required)

Should work without authentication.

  • Request: POST <base-url>/api/readmodel
  • Auth: None
  • Headers: Content-Type: application/json
  • Body:
{
  "query": {
    "queryType": "AuthTest"
  },
  "skip": 0,
  "take": 10
}
  • Expected response (200 OK):
{
  "data": [
    {
      "isAuthenticated": false,
      "authenticationType": "None",
      "roles": [],
      "effectiveRoles": [],
      "message": "Not authenticated - public access",
      "requestTime": "2026-06-18T04:58:18.15Z"
    }
  ],
  "totalCount": 1,
  "skip": 0
}

2. AuthTest Query with Basic Authentication

Should show authenticated user info. Example below is for the seeded system account.

  • Request: POST <base-url>/api/readmodel
  • Auth: Basic Auth (service account)
  • Headers: Content-Type: application/json
  • Body:
{
  "query": {
    "queryType": "AuthTest"
  },
  "skip": 0,
  "take": 10
}
  • Expected response (200 OK):
{
  "data": [
    {
      "isAuthenticated": true,
      "authenticationType": "Basic",
      "roles": ["System", "ServiceAccount", "Member"],
      "effectiveRoles": ["System", "ServiceAccount", "Member", "Admin", "UserManager", "ContentManager", "Public"],
      "message": "Authenticated user with 3 roles, 7 effective roles",
      "requestTime": "2026-06-18T04:58:18.32Z"
    }
  ],
  "totalCount": 1,
  "skip": 0
}

3. CurrentUser Query (Secure — Authentication Required)

Should only return data with authentication. Example below is for the seeded system account.

  • Request: POST <base-url>/api/readmodel
  • Auth: Basic Auth (service account)
  • Headers: Content-Type: application/json
  • Body:
{
  "query": {
    "queryType": "CurrentUser"
  },
  "skip": 0,
  "take": 10
}
  • Expected response (200 OK):
{
  "data": [
    {
      "name": "system@dev.lbs.com",
      "email": "system@dev.lbs.com",
      "roles": ["System", "ServiceAccount", "Member"],
      "claims": {
        "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier": "<user-id>",
        "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name": "system@dev.lbs.com",
        "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress": "system@dev.lbs.com",
        "account_type": "ServiceAccount",
        "internal_user_id": "<user-id>",
        "http://schemas.microsoft.com/ws/2008/06/identity/claims/role": "System, ServiceAccount, Member"
      },
      "authenticationType": "Basic",
      "requestTime": "2026-06-18T04:58:18.41Z",
      "effectiveRoles": ["System", "ServiceAccount", "Member", "Admin", "UserManager", "ContentManager", "Public"]
    }
  ],
  "totalCount": 1,
  "skip": 0
}

4. CurrentUser Query Without Authentication (Should Fail)

Should return empty results (secure-query protection — returns 200, not an error).

  • Request: POST <base-url>/api/readmodel
  • Auth: None
  • Headers: Content-Type: application/json
  • Body:
{
  "query": {
    "queryType": "CurrentUser"
  },
  "skip": 0,
  "take": 10
}
  • Expected response (200 OK):
{
  "data": [],
  "totalCount": 0,
  "skip": 0,
  "take": 10
}

5. AuthTest Query with Admin Service Account

Should show admin + inherited roles. Point the Basic Auth at a requested admin account (see the note above). Example below is for the seeded admin account.

  • Request: POST <base-url>/api/readmodel
  • Auth: Basic Auth (admin service account)
  • Headers: Content-Type: application/json
  • Body:
{
  "query": {
    "queryType": "AuthTest"
  },
  "skip": 0,
  "take": 10
}
  • Expected response (200 OK):
{
  "data": [
    {
      "isAuthenticated": true,
      "authenticationType": "Basic",
      "roles": ["Admin", "ServiceAccount", "UserManager"],
      "effectiveRoles": ["Admin", "ServiceAccount", "UserManager", "ContentManager", "Member", "Public"],
      "message": "Authenticated user with 3 roles, 6 effective roles",
      "requestTime": "2026-06-18T04:58:18.52Z"
    }
  ],
  "totalCount": 1,
  "skip": 0
}

Notes on the Results

  • Public vs secure queries: AuthTest is public (works with or without auth); CurrentUser is secure — without authentication it returns empty results (200, totalCount: 0) rather than an error.
  • roles vs effectiveRoles: roles are the user's assigned roles; effectiveRoles expands them via the role hierarchy. As seen above, the seeded system account expands to 7 effective roles and the admin account to 6. A regular user with no elevated roles still gets Public in effectiveRoles.