Teams
Teams group your application's users together and allow roles to be assigned at the team level. Every member of a team automatically inherits the roles assigned to that team, in addition to any roles assigned to them directly.
How Teams Work
Team "Engineering"
→ Role: developer (permissions: code:push, code:review)
→ Members: user-101, user-102, user-103
user-101 checks "code:push"
→ Direct roles: none with code:push
→ Team roles: developer → code:push ✓
→ Result: allowed
Team-inherited permissions are evaluated alongside direct user permissions in every authorization check. The permission set loaded from cache includes both sources.
Team Fields
| Field | Type | Description |
|---|---|---|
id | UUID | Unique team identifier |
application_id | UUID | Application this team belongs to |
name | string | Team name |
description | string | Optional description |
scope | string | Optional scope to associate the team with a namespace |
metadata | object | Arbitrary key-value metadata |
member_count | integer | Number of members |
created_at | ISO 8601 | Creation timestamp |
List Teams
GET /api/v1/applications/{applicationId}/teams
Requires JWT scope: teams:read
Query parameters:
| Parameter | Description |
|---|---|
search | Filter teams by name (case-insensitive) |
per_page | Results per page (max 100, default 15) |
Response 200 OK:
{
"data": [
{
"id": "018e5f3a-bbbb-7000-8000-000000000010",
"name": "Engineering",
"description": "Core engineering team",
"scope": null,
"metadata": null,
"member_count": 8,
"created_at": "2026-02-01T10:00:00+00:00",
"updated_at": "2026-02-01T10:00:00+00:00"
}
],
"meta": { "current_page": 1, "last_page": 1, "per_page": 15, "total": 1 }
}
Get a Team
GET /api/v1/applications/{applicationId}/teams/{teamId}
Requires JWT scope: teams:read
Returns the team with its full member list and all assigned roles.
Response 200 OK:
{
"data": {
"id": "018e5f3a-bbbb-7000-8000-000000000010",
"name": "Engineering",
"description": "Core engineering team",
"scope": null,
"metadata": null,
"member_count": 2,
"members": [
{
"id": "018e5f3a-0001-7000-8000-000000000020",
"user_id": "user-101",
"added_by": "user-admin",
"created_at": "2026-02-01T10:00:00+00:00"
}
],
"roles": [
{
"id": "018e5f3a-0001-7000-8000-000000000030",
"role": {
"id": "018e5f3a-abcd-7000-8000-000000000001",
"name": "developer",
"display_name": "Developer"
},
"scope": null,
"granted_at": "2026-02-01T10:00:00+00:00",
"expires_at": null
}
],
"created_at": "2026-02-01T10:00:00+00:00",
"updated_at": "2026-02-01T10:00:00+00:00"
}
}
Create a Team
POST /api/v1/applications/{applicationId}/teams
Requires JWT scope: teams:manage
Request body:
| Field | Required | Description |
|---|---|---|
name | Yes | Team name (max 255 chars) |
description | No | Optional description (max 1000 chars) |
scope | No | Optional scope string (max 255 chars) |
metadata | No | Optional JSON object |
curl -X POST \
https://api.yorauth.com/api/v1/applications/your-application-id/teams \
-H "Authorization: Bearer <jwt>" \
-H "Content-Type: application/json" \
-d '{
"name": "Engineering",
"description": "Core engineering team",
"scope": null,
"metadata": { "slack_channel": "#engineering" }
}'
const response = await fetch(
'https://api.yorauth.com/api/v1/applications/your-application-id/teams',
{
method: 'POST',
headers: {
'Authorization': 'Bearer <jwt>',
'Content-Type': 'application/json'
},
body: JSON.stringify({
name: 'Engineering',
description: 'Core engineering team',
metadata: { slack_channel: '#engineering' }
})
}
);
const { data } = await response.json();
Response 201 Created: Returns the created team object.
Update a Team
PUT /api/v1/applications/{applicationId}/teams/{teamId}
Requires JWT scope: teams:manage
All fields are optional.
Request body:
{
"name": "Platform Engineering",
"description": "Updated description"
}
Response 200 OK: Returns the updated team object.
Delete a Team
DELETE /api/v1/applications/{applicationId}/teams/{teamId}
Requires JWT scope: teams:manage
Response 204 No Content on success.
Team Members
List Members
GET /api/v1/applications/{applicationId}/teams/{teamId}/members
Requires JWT scope: teams:read
Response 200 OK:
{
"data": [
{
"id": "018e5f3a-0001-7000-8000-000000000020",
"user_id": "user-101",
"added_by": "user-admin",
"created_at": "2026-02-01T10:00:00+00:00"
}
]
}
Add a Member
POST /api/v1/applications/{applicationId}/teams/{teamId}/members
Requires JWT scope: teams:manage
Request body:
{ "user_id": "user-101" }
Response 201 Created:
{
"data": {
"id": "018e5f3a-0001-7000-8000-000000000020",
"user_id": "user-101",
"created_at": "2026-02-25T14:30:00+00:00"
}
}
Remove a Member
DELETE /api/v1/applications/{applicationId}/teams/{teamId}/members/{userId}
Requires JWT scope: teams:manage
Response 204 No Content on success.
Error responses:
404 Not Found— User is not a member of this teamjson{ "error": { "code": "TEAM_MEMBER_NOT_FOUND", "message": "..." } }
Team Roles
Roles assigned to a team are inherited by all current and future team members.
List Team Roles
GET /api/v1/applications/{applicationId}/teams/{teamId}/roles
Requires JWT scope: teams:read
Response 200 OK:
{
"data": [
{
"id": "018e5f3a-0001-7000-8000-000000000030",
"role": {
"id": "018e5f3a-abcd-7000-8000-000000000001",
"name": "developer",
"display_name": "Developer"
},
"scope": null,
"granted_at": "2026-02-01T10:00:00+00:00",
"expires_at": null
}
]
}
Assign a Role to a Team
POST /api/v1/applications/{applicationId}/teams/{teamId}/roles
Requires JWT scope: teams:manage
Request body:
| Field | Required | Description |
|---|---|---|
role_id | Yes | UUID of the role to assign |
scope | No | Optional scope for this role assignment |
expires_at | No | ISO 8601 expiration datetime |
curl -X POST \
https://api.yorauth.com/api/v1/applications/your-application-id/teams/018e5f3a-bbbb-7000-8000-000000000010/roles \
-H "Authorization: Bearer <jwt>" \
-H "Content-Type: application/json" \
-d '{
"role_id": "018e5f3a-abcd-7000-8000-000000000001",
"scope": null
}'
Response 201 Created:
{
"data": {
"id": "018e5f3a-0001-7000-8000-000000000030",
"role_id": "018e5f3a-abcd-7000-8000-000000000001",
"scope": null,
"granted_at": "2026-02-25T14:30:00+00:00",
"expires_at": null
}
}
Revoke a Role from a Team
DELETE /api/v1/applications/{applicationId}/teams/{teamId}/roles/{roleId}
Requires JWT scope: teams:manage
Query parameters:
| Parameter | Description |
|---|---|
scope | Required if the role was assigned with a scope |
Response 204 No Content on success.
Error responses:
404 Not Found— Role assignment not foundjson{ "error": { "code": "TEAM_ROLE_ASSIGNMENT_NOT_FOUND", "message": "..." } }
Get a User's Teams
GET /api/v1/applications/{applicationId}/users/{userId}/teams
Requires JWT scope: teams:read
Returns all teams the user belongs to, along with the roles each team holds.
Response 200 OK:
{
"data": [
{
"id": "018e5f3a-bbbb-7000-8000-000000000010",
"name": "Engineering",
"description": "Core engineering team",
"scope": null,
"roles": [
{
"role_id": "018e5f3a-abcd-7000-8000-000000000001",
"role_name": "developer",
"scope": null
}
]
}
]
}
Permission Inheritance
When a user is added to a team that has roles assigned, those roles are factored into every subsequent permission check automatically. Specifically:
- The permission cache for the user's application is invalidated (version incremented)
- On the next permission check, both direct user roles and team-inherited roles are loaded into the user's cached permission set
- There is no distinction in the permission check result between direct and team-inherited permissions
Team role assignments support the same scope and expires_at fields as user role assignments. An expired team role is ignored during permission evaluation just like an expired direct role.
Organizations
Organizations are a platform-level concept (for YorAuth dashboard users managing multiple applications collaboratively). They are distinct from the team system described on this page, which operates at the application-user level.
If you are looking for organization-level access control within your application's user base, use teams with scoped role assignments (e.g., scope: "org:acme-corp").
See the Authorization Overview for scoped role examples.