Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
603 changes: 603 additions & 0 deletions src/authorization/authorization.spec.ts

Large diffs are not rendered by default.

91 changes: 91 additions & 0 deletions src/authorization/authorization.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,18 @@ import {
CreatePermissionOptions,
UpdatePermissionOptions,
ListPermissionsOptions,
AuthorizationResource,
AuthorizationResourceResponse,
CreateAuthorizationResourceOptions,
UpdateAuthorizationResourceOptions,
RoleAssignment,
RoleAssignmentResponse,
RoleAssignmentList,
RoleAssignmentListResponse,
ListRoleAssignmentsOptions,
AssignRoleOptions,
RemoveRoleOptions,
RemoveRoleAssignmentOptions,
} from './interfaces';
import {
deserializeEnvironmentRole,
Expand All @@ -39,6 +51,12 @@ import {
deserializePermission,
serializeCreatePermissionOptions,
serializeUpdatePermissionOptions,
deserializeAuthorizationResource,
serializeCreateResourceOptions,
serializeUpdateResourceOptions,
deserializeRoleAssignment,
serializeAssignRoleOptions,
serializeRemoveRoleOptions,
} from './serializers';

export class Authorization {
Expand Down Expand Up @@ -238,4 +256,77 @@ export class Authorization {
async deletePermission(slug: string): Promise<void> {
await this.workos.delete(`/authorization/permissions/${slug}`);
}

async getResource(resourceId: string): Promise<AuthorizationResource> {
const { data } = await this.workos.get<AuthorizationResourceResponse>(
`/authorization/resources/${resourceId}`,
);
return deserializeAuthorizationResource(data);
}

async createResource(
options: CreateAuthorizationResourceOptions,
): Promise<AuthorizationResource> {
const { data } = await this.workos.post<AuthorizationResourceResponse>(
'/authorization/resources',
serializeCreateResourceOptions(options),
);
return deserializeAuthorizationResource(data);
}

async updateResource(
options: UpdateAuthorizationResourceOptions,
): Promise<AuthorizationResource> {
const { data } = await this.workos.patch<AuthorizationResourceResponse>(
`/authorization/resources/${options.resourceId}`,
serializeUpdateResourceOptions(options),
);
return deserializeAuthorizationResource(data);
}

async deleteResource(resourceId: string): Promise<void> {
await this.workos.delete(`/authorization/resources/${resourceId}`);
}

// phase 3
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// phase 3

async listRoleAssignments(
options: ListRoleAssignmentsOptions,
): Promise<RoleAssignmentList> {
const { organizationMembershipId, ...queryOptions } = options;
const { data } = await this.workos.get<RoleAssignmentListResponse>(
`/authorization/organization_memberships/${organizationMembershipId}/role_assignments`,
{ query: queryOptions },
);
return {
object: 'list',
data: data.data.map(deserializeRoleAssignment),
listMetadata: {
before: data.list_metadata.before,
after: data.list_metadata.after,
},
};
}

async assignRole(options: AssignRoleOptions): Promise<RoleAssignment> {
const { data } = await this.workos.post<RoleAssignmentResponse>(
`/authorization/organization_memberships/${options.organizationMembershipId}/role_assignments`,
serializeAssignRoleOptions(options),
);
return deserializeRoleAssignment(data);
}

async removeRole(options: RemoveRoleOptions): Promise<void> {
await this.workos.delete(
`/authorization/organization_memberships/${options.organizationMembershipId}/role_assignments`,
serializeRemoveRoleOptions(options),
);
}

async removeRoleAssignment(
options: RemoveRoleAssignmentOptions,
): Promise<void> {
await this.workos.delete(
`/authorization/organization_memberships/${options.organizationMembershipId}/role_assignments/${options.roleAssignmentId}`,
);
}
}
12 changes: 12 additions & 0 deletions src/authorization/fixtures/authorization-resource.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"object": "authorization_resource",
"id": "authz_resource_01HXYZ123ABC456DEF789ABC",
"external_id": "doc-456",
"name": "Q4 Budget Report",
"description": "Financial report for Q4 2025",
"resource_type_slug": "document",
"organization_id": "org_01HXYZ123ABC456DEF789ABC",
"parent_resource_id": "authz_resource_01HXYZ123ABC456DEF789XYZ",
"created_at": "2024-01-15T09:30:00.000Z",
"updated_at": "2024-01-15T09:30:00.000Z"
}
23 changes: 23 additions & 0 deletions src/authorization/fixtures/list-role-assignments.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"object": "list",
"data": [
{
"object": "role_assignment",
"id": "ra_01HXYZ123ABC456DEF789ABC",
"role": {
"slug": "editor"
},
"resource": {
"id": "resource_01HXYZ123ABC456DEF789XYZ",
"external_id": "doc-123",
"resource_type_slug": "document"
},
"created_at": "2024-01-15T09:30:00.000Z",
"updated_at": "2024-01-15T09:30:00.000Z"
}
],
"list_metadata": {
"before": null,
"after": "ra_01HXYZ123ABC456DEF789ABC"
}
}
14 changes: 14 additions & 0 deletions src/authorization/fixtures/role-assignment.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"object": "role_assignment",
"id": "ra_01HXYZ123ABC456DEF789ABC",
"role": {
"slug": "editor"
},
"resource": {
"id": "resource_01HXYZ123ABC456DEF789XYZ",
"external_id": "doc-123",
"resource_type_slug": "document"
},
"created_at": "2024-01-15T09:30:00.000Z",
"updated_at": "2024-01-15T09:30:00.000Z"
}
14 changes: 14 additions & 0 deletions src/authorization/interfaces/assign-role-options.interface.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
export interface AssignRoleOptions {
organizationMembershipId: string;
roleSlug: string;
resourceId?: string;
resourceExternalId?: string;
resourceTypeSlug?: string;
}

export interface SerializedAssignRoleOptions {
role_slug: string;
resource_id?: string;
resource_external_id?: string;
resource_type_slug?: string;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
export interface AuthorizationResource {
object: 'authorization_resource';
id: string;
externalId: string;
name: string;
description: string | null;
resourceTypeSlug: string;
organizationId: string;
parentResourceId: string | null;
createdAt: string;
updatedAt: string;
}

export interface AuthorizationResourceResponse {
object: 'authorization_resource';
id: string;
external_id: string;
name: string;
description: string | null;
resource_type_slug: string;
organization_id: string;
parent_resource_id: string | null;
created_at: string;
updated_at: string;
}

export interface CreateAuthorizationResourceOptions {
externalId: string;
name: string;
description?: string | null;
resourceTypeSlug: string;
organizationId: string;
parentResourceId?: string | null;
}

export interface SerializedCreateAuthorizationResourceOptions {
external_id: string;
name: string;
description?: string | null;
resource_type_slug: string;
organization_id: string;
parent_resource_id?: string | null;
}

export interface UpdateAuthorizationResourceOptions {
resourceId: string;
name?: string;
description?: string | null;
}

export interface SerializedUpdateAuthorizationResourceOptions {
name?: string;
description?: string | null;
}
6 changes: 6 additions & 0 deletions src/authorization/interfaces/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,9 @@ export * from './permission.interface';
export * from './create-permission-options.interface';
export * from './update-permission-options.interface';
export * from './list-permissions-options.interface';
export * from './authorization-resource.interface';
export * from './role-assignment.interface';
export * from './list-role-assignments-options.interface';
export * from './assign-role-options.interface';
export * from './remove-role-options.interface';
export * from './remove-role-assignment-options.interface';
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { PaginationOptions } from '../../common/interfaces/pagination-options.interface';
export interface ListRoleAssignmentsOptions extends PaginationOptions {
organizationMembershipId: string;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export interface RemoveRoleAssignmentOptions {
organizationMembershipId: string;
roleAssignmentId: string;
}
14 changes: 14 additions & 0 deletions src/authorization/interfaces/remove-role-options.interface.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
export interface RemoveRoleOptions {
organizationMembershipId: string;
roleSlug: string;
resourceId?: string;
resourceExternalId?: string;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if we should actually make resource argument this for all endpoints

resource: {id: string} | {external_id: string, type_slug: string}

Because we also have it for remove/assign role options

It could be a union of types

type ResourceOptions = {id: string} | {external_id: string, type_slug: string}[3:17 PM]export interface RemoveRoleOptions {
  organizationMembershipId: string;
  roleSlug: string;
  resource: ResourceOptions
}

resourceTypeSlug?: string;
}

export interface SerializedRemoveRoleOptions {
role_slug: string;
resource_id?: string;
resource_external_id?: string;
resource_type_slug?: string;
}
51 changes: 51 additions & 0 deletions src/authorization/interfaces/role-assignment.interface.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
export interface RoleAssignmentRole {
slug: string;
}

export interface RoleAssignmentResource {
id: string;
externalId: string;
resourceTypeSlug: string;
}

export interface RoleAssignmentResourceResponse {
id: string;
external_id: string;
resource_type_slug: string;
}

export interface RoleAssignment {
object: 'role_assignment';
id: string;
role: RoleAssignmentRole;
resource: RoleAssignmentResource;
createdAt: string;
updatedAt: string;
}

export interface RoleAssignmentResponse {
object: 'role_assignment';
id: string;
role: RoleAssignmentRole; // Note: role.slug is already snake_case compatible
resource: RoleAssignmentResourceResponse;
created_at: string;
updated_at: string;
}

export interface RoleAssignmentList {
object: 'list';
data: RoleAssignment[];
listMetadata: {
before: string | null;
after: string | null;
};
}

export interface RoleAssignmentListResponse {
object: 'list';
data: RoleAssignmentResponse[];
list_metadata: {
before: string | null;
after: string | null;
};
}
17 changes: 17 additions & 0 deletions src/authorization/serializers/assign-role-options.serializer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import {
AssignRoleOptions,
SerializedAssignRoleOptions,
} from '../interfaces/assign-role-options.interface';

export const serializeAssignRoleOptions = (
options: AssignRoleOptions,
): SerializedAssignRoleOptions => ({
role_slug: options.roleSlug,
...(options.resourceId && { resource_id: options.resourceId }),
...(options.resourceExternalId && {
resource_external_id: options.resourceExternalId,
}),
...(options.resourceTypeSlug && {
resource_type_slug: options.resourceTypeSlug,
}),
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import {
AuthorizationResource,
AuthorizationResourceResponse,
} from '../interfaces/authorization-resource.interface';

export const deserializeAuthorizationResource = (
resource: AuthorizationResourceResponse,
): AuthorizationResource => ({
object: resource.object,
id: resource.id,
externalId: resource.external_id,
name: resource.name,
description: resource.description,
resourceTypeSlug: resource.resource_type_slug,
organizationId: resource.organization_id,
parentResourceId: resource.parent_resource_id,
createdAt: resource.created_at,
updatedAt: resource.updated_at,
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import {
CreateAuthorizationResourceOptions,
SerializedCreateAuthorizationResourceOptions,
} from '../interfaces/authorization-resource.interface';

export const serializeCreateResourceOptions = (
options: CreateAuthorizationResourceOptions,
): SerializedCreateAuthorizationResourceOptions => ({
organization_id: options.organizationId,
resource_type_slug: options.resourceTypeSlug,
external_id: options.externalId,
name: options.name,
...(options.description !== undefined && {
description: options.description,
}),
...(options.parentResourceId !== undefined && {
parent_resource_id: options.parentResourceId,
}),
});
6 changes: 6 additions & 0 deletions src/authorization/serializers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,9 @@ export * from './update-organization-role-options.serializer';
export * from './permission.serializer';
export * from './create-permission-options.serializer';
export * from './update-permission-options.serializer';
export * from './authorization-resource.serializer';
export * from './create-authorization-resource-options.serializer';
export * from './update-authorization-resource-options.serializer';
export * from './role-assignment.serializer';
export * from './assign-role-options.serializer';
export * from './remove-role-options.serializer';
Loading