Skip to main content
Securing a Sutro Generated App (SGA) is a crucial part of building a robust application. Sutro provides a flexible and powerful security model that centers around the concepts of Subject, Principal, and Identity. Understanding these core concepts is key to effectively implementing authentication and authorization in your SGA.

Core concepts

Subject

A Subject is any external entity that can make a request of an SGA. Most commonly, a Subject is a human user interacting with the app through a client, but it could also be a service account, an automated process, or any other external caller. The key characteristic of a Subject is that it exists outside the application boundary and initiates interactions with it. A Subject on its own is opaque to the application — the app does not inherently know anything about who or what is making the request. That information comes from Principals and Identities.

Principal

A Principal is a security-relevant fact about a Subject. Principals describe what is known about a Subject in a way that matters for security decisions. Examples of Principals include:
  • A username or email address
  • A role or group membership (e.g. “admin”, “teacher”)
  • An organization affiliation
  • An API key identifier
A single Subject can have many Principals. For instance, a user might simultaneously be known by their email address, their role within an organization, and their membership in several groups. Each of these is a distinct Principal that can inform authorization decisions.

Identity

An Identity is a special kind of Principal: one that is verifiable and can be used to uniquely identify a Subject. While any Principal carries security-relevant information, an Identity carries proof — it is backed by a credential that the application can validate. Examples of Identities include:
  • An authenticated session (established via username/password login)
  • A verified JWT token
  • An OAuth access token tied to a specific user
  • An API key with a known owner
The distinction matters: a Principal such as “has the admin role” is a fact about a Subject, but it is not sufficient to identify them. An Identity like “authenticated as [email protected] via a valid session token” both identifies the Subject and can be verified by the application.

How they relate

When a request arrives at an SGA:
  1. The app examines the request for credentials and establishes an Identity (authentication).
  2. From the Identity, the app resolves the full set of Principals associated with the Subject — their roles, memberships, permissions, and other security-relevant facts.
  3. These Principals are bundled into a runtime Subject context, exposed in SLang as @subject, which is then used for authorization checks.

How authorization works

When an incoming request reaches an SGA, it passes through a series of stages before the trigger logic is allowed to execute. Each stage builds on the previous one, transforming a raw HTTP request into an authorized action.

1. Extract credentials

The app inspects the incoming request for authentication credentials. This could be a session cookie, a Bearer token in the Authorization header, an API key, or another supported credential type. If no credentials are present and the trigger requires authentication, the request is rejected immediately with a 401 Unauthorized response.

2. Establish Identity

The extracted credentials are validated — for example, verifying a JWT signature or looking up a session in the database. If validation succeeds, an Identity is established: the app now has a verified claim about who is making the request.

3. Resolve Principals

Using the established Identity, the app looks up the full set of Principals associated with the Subject. The SGA handles this for you. For example, a user identified by their session might be resolved to Principals like “member of Organization X with the teacher role” and “has permissions lesson:generate, lesson:read”.

4. Build the runtime Subject

The resolved Principals are assembled into the runtime Subject context. In SLang, this is exposed as @subject and carries everything the authorization layer needs to make access decisions — the authenticated identity, roles, memberships, and permissions.

5. Evaluate trigger auth rules

The trigger’s auth block is evaluated. This can be any expression, but generally involves the internal @subject value. SLang supports several forms of authorization check (detailed in the next section). If the Subject satisfies the auth rules, the trigger executes. If not, the request is rejected with a 403 Forbidden response.

Defining Subjects, Identities, and Groups

By default, an SGA has no security model — no users, groups, or permissions. In order to create a secure app, you need to describe which of your entities should be treated as Subjects and which properties of those entities should be treated as Identities. Making an entity into a Subject is easy; simply add a subject keyword to your entity description:
entity User
  subject
  fields
    name: TEXT
    email: TEXT
You can decide which field (or fields) of that entity should be treated as an Identity. This is done by adding the identity keyword.
entity User
  subject
  identity email
  fields
    name: TEXT
    email: TEXT
It’s important to remember that, while we are using an entity called User in these examples, an SGA makes no special assumptions about any entity based on its name. You could just as easily have an entity called Teacher or Customer that is marked as a Subject and has an Identity field. At this point, you have an SGA that will support registration and login of users based on their email address.

Group Membership

A common pattern for secure apps is to support the idea of a group. A group is a collection of Subjects that can be treated as a unit for authorization purposes. For example, you might have an Organization entity that represents a company or school, and users can be members of one or more organizations. Membership in a group is another kind of Principal that can be used in authorization checks. To designate an entity as a group, you can use the group keyword, along with the field that serves as the unique identifier for that group. Commonly, this will be the internal @id field.
entity Organization
  group @id
  fields
    name: TEXT
Then, you can have a Membership entity that links User Subjects to Organization groups. This membership can carry additional information, such as the user’s role within that organization, which can be used for more fine-grained authorization.
enum MembershipRole
  values
    owner
    editor
    reader

entity User
  subject
  identity email
  ;; fields omitted for brevity

entity Organization
  group @id
  ;; fields omitted for brevity

entity Membership
  role membershipRole
  fields
    membershipRole: MembershipRole

relation  User[Memberships] 1 --- 0..* Membership[Member]
relation  Organization[Members] 1 --- 0..* Membership[Organization]
Now, we have described our users, groups and roles. The SGA will automatically resolve the Principals for a Subject based on this data model.

Defining Permissions

For some applications, it’s sufficient to check for group membership or role membership in authorization rules. For others, you may want to define specific permissions that can be granted to users or groups, and check for those permissions in your triggers. SLang supports the ability to define permissions and associate them with Principals. This is done using the permissions keyword, which allows you to specify which permissions are granted to which Principals.
permissions User->memberships->owner
  "lesson:generate"
  "lesson:read"
Permissions are attached to a role by describing a path from the User subject to the relevant role or group membership. In this example, any user who has a Membership with the owner role will be granted the lesson:generate and lesson:read permissions.

Authorization in SLang triggers

SLang expresses authorization directly in each trigger via an auth block. For triggers that don’t require any authentication or authorization, the auth block can simply be omitted. In this case, the trigger will be open to any caller. Below are some examples.

1) Permission check

trigger CreateOrder on HttpRequest
  description "HTTP endpoint to create a new order."
  endpoint POST /organizations/{organizationId}/orders
  arguments
    organization := @subject.organization
    items := @request.body.items
    shippingStreet := @request.body.shippingStreet
    shippingCity := @request.body.shippingCity
    shippingState := @request.body.shippingState
    shippingZip := @request.body.shippingZip
    notes := @request.body.notes
  auth
    @subject can "order:create"
Interpretation: the Subject must have an order:create permission assigned to them.

2) Authenticated-only access

trigger GetTask on HttpRequest
  description "Get a single task."
  endpoint GET /tasks/{taskId}
  arguments
    taskId := @request.path.taskId
  auth
    @subject is @defined
Interpretation: any authenticated Subject is allowed.

3) Permission scoped to an organization

trigger CreateReferenceMaterial on HttpRequest
  description "Create a curriculum or planning reference document."
  endpoint POST /organizations/{organizationId}/reference-materials
  arguments
    organization := @request.path.organizationId
    title := @request.query.title
    materialType := @request.query.materialType
    summary := @request.query.summary
    file := @request.files.file
    fileName := @request.query.fileName
    contentType := @request.query.contentType
  auth
    @subject can "lesson:generate" in Organization(@request.path.organizationId)
Interpretation: the Subject must have lesson:generate permission in that specific Organization.

Security endpoints

When you define a subject in a SLang file, the resulting SGA will automatically include two new endpoints.

Registration endpoint

To register a user with an SGA, clients can send a POST request to the /register endpoint with the necessary information to create a new Subject.
identity
string
required
The identity of the new Subject. For example, if the Identity is based on an email field, this would be the user’s email address.
password
string
required
The password of the new Subject.
This will return a 201 Created response if the registration is successful, and some authentication tokens:
accessToken
string
A token that can be used to authenticate future requests.
refreshToken
string
A token that can be used to obtain a new access token when the current one expires.

Login endpoint

To log in to an SGA, clients can send a POST request to the /login endpoint with the credentials of an existing Subject.
identity
string
required
The identity of the existing Subject. For example, if the Identity is based on an email field, this would be the user’s email address.
password
string
required
The password of the existing Subject.
This will return a 200 OK response if the login is successful, and some authentication tokens:
accessToken
string
A token that can be used to authenticate future requests.
refreshToken
string
A token that can be used to obtain a new access token when the current one expires.

Summary

At this point, you have all the information you need to start modeling security in your SGA.