Protecting Systems with SGNL Using AuthZEN-Compliant Custom Transforms

Introduction

This guide explains how to configure a SGNL Protected System with a Custom Transform that formats SGNL Access API responses to conform to the OpenID AuthZEN Authorization API 1.0 standard. This enables your Protected System to act as an AuthZEN-compliant Policy Enforcement Point (PEP), receiving decisions from SGNL as the Policy Decision Point (PDP) in a standardized format.

Prerequisites

  • A SGNL Client
  • A SGNL User Account with at least Protected System Admin privileges
  • At least one Protected System configured in SGNL
  • At least one system of record integrated to SGNL containing principals and (optionally) assets

Background: SGNL and AuthZEN

The AuthZEN Authorization API 1.0 standard defines a common interface between Policy Enforcement Points (PEPs) and Policy Decision Points (PDPs). SGNL is a co-author of this standard. SGNL’s Access API returns decisions in its own native format; using a Custom Transform, you can reformat those responses to match the AuthZEN schema, enabling interoperability with any AuthZEN-compliant system.

AuthZEN Access Evaluation Response Schema

A single AuthZEN Access Evaluation response looks like this:

{
  "decision": true
}

With optional context:

{
  "decision": false,
  "context": {
    "reason_admin": {
      "403": "Request failed policy C076E82F"
    },
    "reason_user": {
      "403": "Insufficient privileges. Contact your administrator"
    }
  }
}

The decision field is a boolean (true = allow, false = deny) — note that SGNL’s native API returns string values ("Allow" / "Deny"), so the transform must handle this conversion.


Step 1: Create or Select a Protected System

  1. Log in to your SGNL Client with an Admin Account
  2. Navigate to Protected Systems and select an existing Protected System, or create a new one
  3. Configure your principal identifier, assets, default policy, and authentication token as described in the standard Protected System setup

Step 2: Configure the Request Mapping

The Request mapping tells SGNL how to extract the principal, action, and asset from the incoming AuthZEN request payload. Navigate to the Request tab of your Protected System configuration.

An AuthZEN Access Evaluation request has the following structure:

{
  "subject": {
    "type": "user",
    "id": "[email protected]"
  },
  "evaluations": [
    {
      "action": {
        "name": "can_read"
      },
      "resource": {
        "type": "account",
        "id": "123"
      }
    }
  ]
}

Configure the mapped fields as follows:

Mapped FieldAccess API Parameter
{$.subject.id}id
(leave blank)ipAddress (Optional)
{$.evaluations.*.action.name}query.action
{$.evaluations.*.resource.id}query.assetId

Note: subject.type and resource.type are not mapped here — asset types are managed through your Protected System’s asset type configuration rather than the request mapper.


Step 3: Configure the Custom Transform

Navigate to the Transforms tab of your Protected System configuration.

Access Evaluation Transform

This transform maps a SGNL Access API response to the AuthZEN Access Evaluation response format (Section 6.2 of the spec).

  1. Within your Protected System, select the Transforms tab
  2. Choose Access Transform
  3. Select Custom as the transform type
  4. Enter the following template:
{{- /* AuthZEN Access Evaluations Transform - Boxcarred Decisions */ -}}
{
  "evaluations": [
    {{- range $i, $item := .decisions}}{{if $i}},{{end}}
    {
      "decision": {{if eq $item.decision "Allow"}}true{{else}}false{{end}}{{if $item.assetId}},
      "context": {
        "resource_id": "{{$item.assetId}}"
      }{{end}}
    }
    {{- end}}
  ]
}
  1. Click Save

Note: To receive a transformed response, append ?transform=true to your Access API request URL. For example: https://your-tenant.sgnlapis.cloud/access/v2/evaluations?transform=true


For richer AuthZEN compliance, include decision context such as reason codes and policy metadata. This aligns with the AuthZEN Decision Context specification (Section 5.5.1):

{{- /* AuthZEN Access Evaluations Transform with Context */ -}}
{
  "evaluations": [
    {{- range $i, $item := .decisions}}{{if $i}},{{end}}
    {
      "decision": {{if eq $item.decision "Allow"}}true{{else}}false{{end}},
      "context": {
        {{- if $item.assetId}}
        "resource_id": "{{$item.assetId}}",
        {{- end}}
        "reason_admin": {
          "{{if eq $item.decision "Allow"}}200{{else}}403{{end}}": "{{if eq $item.decision "Allow"}}Access granted{{else}}Access denied by SGNL policy{{end}}"
        },
        "reason_user": {
          "{{if eq $item.decision "Allow"}}200{{else}}403{{end}}": "{{if eq $item.decision "Allow"}}Access permitted{{else}}Insufficient privileges. Contact your administrator{{end}}"
        },
        "evaluation_time_ms": {{$.evaluationDuration}}
      }
    }
    {{- end}}
  ]
}

Step 4: Calling the AuthZEN-Compliant Endpoint

Once the request mapping and transform are configured, your Protected System (acting as the PEP) should send AuthZEN-formatted requests to SGNL with ?transform=true. SGNL will extract the principal, action, and asset using the request mapping, evaluate the access decision, and return a response in the AuthZEN format via the transform.

Example Request

POST /access/v2/evaluations?transform=true HTTP/1.1
Host: clientName.sgnlapis.cloud
Content-Type: application/json
Authorization: Bearer <your-sgnl-token>
{
  "subject": {
    "type": "user",
    "id": "[email protected]"
  },
  "action": {
    "name": "can_read"
  },
  "resource": {
    "type": "account",
    "id": "123"
  }
}

Example AuthZEN-Compliant Response

{
  "evaluations": [
    {
      "decision": true,
      "context": {
        "resource_id": "123",
        "reason_admin": {
          "200": "Access granted"
        },
        "reason_user": {
          "200": "Access permitted"
        },
        "evaluation_time_ms": 12
      }
    }
  ]
}

AuthZEN Compliance Reference

The following table maps AuthZEN concepts to their SGNL equivalents:

AuthZEN ConceptAuthZEN FieldSGNL EquivalentRequest Mapping
Subjectsubject.idprincipalId{$.subject.id}id
Resourceresource.idassetId{$.evaluations.*.resource.id}query.assetId
Actionaction.nameaction{$.evaluations.*.action.name}query.action
Decision (allow)"decision": true"decision": "Allow"Handled by transform
Decision (deny)"decision": false"decision": "Deny"Handled by transform
Decision Contextcontext objectCustom via transformHandled by transform

Best Practices

  1. Start in Simulated mode — Assign policies in Simulated enforcement mode first to validate decisions before enforcing them.
  2. Handle missing assets — Use conditional logic in your transform to gracefully handle cases where assetId may be absent.
  3. Boolean conversion is critical — AuthZEN requires a JSON boolean for decision; always use {{if eq $item.decision "Allow"}}true{{else}}false{{end}} rather than passing the SGNL string value directly.
  4. Test with ?transform=true — Validate your transform output before connecting your Protected System by calling the API directly and inspecting the response.
  5. Monitor via SGNL Logs — After connecting your Protected System, use the SGNL Logs view to confirm requests are being received and decisions are being returned as expected.

Further Resources