Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
01556e7
feat: align with api repo versions
obany Aug 17, 2026
f20a690
feat: package refactoring
obany Aug 17, 2026
d331ee3
feat: authentication user remove roles
obany Aug 17, 2026
82568f7
feat: align with api repo versions
obany Aug 19, 2026
4e4088c
feat: align with api repo versions
obany Aug 20, 2026
86ef217
feat: update route defaults
obany Aug 21, 2026
a6a0a23
chore: update lint rules
obany Aug 21, 2026
72bf20e
chore: align versions
obany Aug 24, 2026
2994961
chore: update dependencies
obany Aug 25, 2026
74ef3e8
feat: update config
obany Aug 25, 2026
4613a66
feat: single default permission
obany Aug 26, 2026
3dd7835
feat: replace permission with authorization
obany Aug 26, 2026
fdba651
feat: verify scope on migration
obany Aug 26, 2026
00d8b48
feat: verify scope on migration
obany Aug 26, 2026
d87decb
feat: route permissions
obany Aug 27, 2026
f23b171
feat: pr comments
obany Aug 28, 2026
cbacb1a
feat: pr comments
obany Aug 28, 2026
54e8b3d
feat: pr comments
obany Sep 2, 2026
5f66f15
feat: add password policy endpoint
obany Sep 3, 2026
2aa1ac0
Merge branch 'next' into feature/authorization
obany Sep 9, 2026
97b2764
Merge remote-tracking branch 'origin/next' into feature/authorization
obany Oct 6, 2026
1b86af2
Merge remote-tracking branch 'origin/next' into feature/authorization
obany Oct 22, 2026
1ebf5c7
Merge remote-tracking branch 'origin/next' into feature/authorization
obany Oct 23, 2026
099e820
feat: updated ts compile
obany Oct 23, 2026
271f8a8
Merge remote-tracking branch 'origin/next' into feature/authorization
obany Oct 23, 2026
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
9 changes: 6 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
# 3Sixty API
# 3Sixty API Auth

This repository provides a modular API stack for defining contracts, implementing services, exposing server endpoints, and consuming those endpoints from client applications. The packages are designed to work together so teams can compose reliable API capabilities without duplicating cross-cutting concerns such as routing, request processing, authentication, and tenant context handling.
This repository provides authentication for the 3Sixty API stack, covering sign-in, token refresh, password management and user administration backed by entity storage, with an auth header processor that resolves the caller for each request.

Alongside the core API building blocks, the repository also includes entity storage authentication and tenant processing components that can be adopted independently or integrated into a broader platform architecture. The overall goal is to keep API development consistent, maintainable, and straightforward to extend across different deployment contexts.
Alongside these flows, the repository includes authentication audit logging, rate limiting of sensitive actions and a tenant override processor that lets callers holding the escalated privilege role act on another tenant. Route access is governed by the authorization packages, so each route declares its default authorization rather than checking scopes itself.

## Packages

- [api-auth-models](packages/api-auth-models/README.md) - Contracts for authentication audit and rate limiting.
- [api-auth-service](packages/api-auth-service/README.md) - Authentication audit and rate limiting services, tenant override processing and audit REST routes backed by entity storage.
- [api-auth-rest-client](packages/api-auth-rest-client/README.md) - REST client for the authentication audit endpoints.
- [api-auth-entity-storage-models](packages/api-auth-entity-storage-models/README.md) - Contracts for authentication flows and admin user management with entity storage.
- [api-auth-entity-storage-service](packages/api-auth-entity-storage-service/README.md) - Authentication service implementation and REST routes backed by entity storage.
- [api-auth-entity-storage-rest-client](packages/api-auth-entity-storage-rest-client/README.md) - REST clients for authentication and admin operations against entity storage endpoints.
Expand Down
68 changes: 18 additions & 50 deletions docs/packages.md
Original file line number Diff line number Diff line change
@@ -1,52 +1,28 @@
# API Packages
# API Auth Packages

## api-models
## api-auth-models

This package provides shared API contracts, route types, and response models used across services and clients.
This package provides contracts for authentication audit and rate limiting.

- [README](../packages/api-models/README.md)
- [Examples](../packages/api-models/docs/examples.md)
- [Changelog](../packages/api-models/docs/changelog.md)
- [README](../packages/api-auth-models/README.md)
- [Examples](../packages/api-auth-models/docs/examples.md)
- [Changelog](../packages/api-auth-models/docs/changelog.md)

## api-core
## api-auth-service

This package provides base client classes and common helpers for building HTTP and socket integrations.
This package provides authentication audit and rate limiting services, tenant override processing and audit REST routes backed by entity storage.

- [README](../packages/api-core/README.md)
- [Examples](../packages/api-core/docs/examples.md)
- [Changelog](../packages/api-core/docs/changelog.md)
- [README](../packages/api-auth-service/README.md)
- [Examples](../packages/api-auth-service/docs/examples.md)
- [Changelog](../packages/api-auth-service/docs/changelog.md)

## api-processors
## api-auth-rest-client

This package provides reusable request and route processors for logging, context handling, and content negotiation.
This package provides rEST client for the authentication audit endpoints.

- [README](../packages/api-processors/README.md)
- [Examples](../packages/api-processors/docs/examples.md)
- [Changelog](../packages/api-processors/docs/changelog.md)

## api-server-fastify

This package provides Fastify web server integration for exposing API routes with consistent runtime behaviour. It builds on the [Fastify](https://fastify.dev/) framework to offer a predictable hosting layer for API services.

- [README](../packages/api-server-fastify/README.md)
- [Examples](../packages/api-server-fastify/docs/examples.md)
- [Changelog](../packages/api-server-fastify/docs/changelog.md)

## api-service

This package provides information and hosting service implementations with generated REST route handlers.

- [README](../packages/api-service/README.md)
- [Examples](../packages/api-service/docs/examples.md)
- [Changelog](../packages/api-service/docs/changelog.md)

## api-rest-client

This package provides a REST client implementation for consuming information and hosting endpoints.

- [README](../packages/api-rest-client/README.md)
- [Examples](../packages/api-rest-client/docs/examples.md)
- [Changelog](../packages/api-rest-client/docs/changelog.md)
- [README](../packages/api-auth-rest-client/README.md)
- [Examples](../packages/api-auth-rest-client/docs/examples.md)
- [Changelog](../packages/api-auth-rest-client/docs/changelog.md)

## api-auth-entity-storage-models

Expand All @@ -58,24 +34,16 @@ This package provides contracts for authentication flows and admin user manageme

## api-auth-entity-storage-service

This package provides an authentication service implementation and REST routes backed by entity storage.
This package provides authentication service implementation and REST routes backed by entity storage.

- [README](../packages/api-auth-entity-storage-service/README.md)
- [Examples](../packages/api-auth-entity-storage-service/docs/examples.md)
- [Changelog](../packages/api-auth-entity-storage-service/docs/changelog.md)

## api-auth-entity-storage-rest-client

This package provides REST clients for authentication and admin operations against entity storage endpoints.
This package provides rEST clients for authentication and admin operations against entity storage endpoints.

- [README](../packages/api-auth-entity-storage-rest-client/README.md)
- [Examples](../packages/api-auth-entity-storage-rest-client/docs/examples.md)
- [Changelog](../packages/api-auth-entity-storage-rest-client/docs/changelog.md)

## api-tenant-processor

This package provides tenant resolution services and route handlers that derive tenant context from API keys.

- [README](../packages/api-tenant-processor/README.md)
- [Examples](../packages/api-tenant-processor/docs/examples.md)
- [Changelog](../packages/api-tenant-processor/docs/changelog.md)
21 changes: 15 additions & 6 deletions packages/api-auth-entity-storage-models/docs/examples.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,7 @@ const createRequest: IAdminUserCreateRequest = {
email: 'bob@example.org',
password: 'initial-password',
userIdentity: 'did:example:bob',
organizationIdentity: 'did:example:org',
scope: ['admin', 'auditor']
organizationIdentity: 'did:example:org'
}
};

Expand All @@ -57,24 +56,34 @@ const updateRequest: IAdminUserUpdateRequest = {
email: 'bob@example.org'
},
body: {
userIdentity: 'did:example:bob:ops',
scope: ['admin']
userIdentity: 'did:example:bob:ops'
}
};

console.log(createRequest.body.scope.length); // 2
console.log(updateRequest.body.userIdentity); // did:example:bob:ops
```

## Authentication Responses

```typescript
import type { ILoginResponse } from '@3sixty/api-auth-entity-storage-models';
import type {
ILoginResponse,
IPasswordPolicyResponse
} from '@3sixty/api-auth-entity-storage-models';

const loginResponse: ILoginResponse = {
body: {
expiry: 3600
}
};

const passwordPolicyResponse: IPasswordPolicyResponse = {
body: {
minPasswordLength: 8,
maxPasswordLength: 128
}
};

console.log(loginResponse.body.expiry); // 3600
console.log(passwordPolicyResponse.body.minPasswordLength); // 8
```
19 changes: 0 additions & 19 deletions packages/api-auth-entity-storage-models/docs/reference/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,7 @@
## Interfaces

- [IAuthenticationAdminComponent](interfaces/IAuthenticationAdminComponent.md)
- [IAuthenticationAuditComponent](interfaces/IAuthenticationAuditComponent.md)
- [IAuthenticationAuditEntry](interfaces/IAuthenticationAuditEntry.md)
- [IAuthenticationComponent](interfaces/IAuthenticationComponent.md)
- [IAuthenticationRateActionConfig](interfaces/IAuthenticationRateActionConfig.md)
- [IAuthenticationRateComponent](interfaces/IAuthenticationRateComponent.md)
- [IAuthenticationUser](interfaces/IAuthenticationUser.md)
- [IAuthenticationUserSecure](interfaces/IAuthenticationUserSecure.md)
- [IAdminUserCreateRequest](interfaces/IAdminUserCreateRequest.md)
Expand All @@ -17,24 +13,9 @@
- [IAdminUserRemoveRequest](interfaces/IAdminUserRemoveRequest.md)
- [IAdminUserUpdatePasswordRequest](interfaces/IAdminUserUpdatePasswordRequest.md)
- [IAdminUserUpdateRequest](interfaces/IAdminUserUpdateRequest.md)
- [IAuditCreateRequest](interfaces/IAuditCreateRequest.md)
- [IAuditGetRequest](interfaces/IAuditGetRequest.md)
- [IAuditGetResponse](interfaces/IAuditGetResponse.md)
- [IAuditQueryRequest](interfaces/IAuditQueryRequest.md)
- [IAuditQueryResponse](interfaces/IAuditQueryResponse.md)
- [IAuditRemoveRequest](interfaces/IAuditRemoveRequest.md)
- [IAuditUpdateRequest](interfaces/IAuditUpdateRequest.md)
- [ILoginRequest](interfaces/ILoginRequest.md)
- [ILoginResponse](interfaces/ILoginResponse.md)
- [ILogoutRequest](interfaces/ILogoutRequest.md)
- [IRefreshTokenRequest](interfaces/IRefreshTokenRequest.md)
- [IRefreshTokenResponse](interfaces/IRefreshTokenResponse.md)
- [IUpdatePasswordRequest](interfaces/IUpdatePasswordRequest.md)

## Type Aliases

- [AuthAuditEvent](type-aliases/AuthAuditEvent.md)

## Variables

- [AuthAuditEvent](variables/AuthAuditEvent.md)
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,3 @@ The user identity.
> **organizationIdentity**: `string`

The users organization.

***

### scope {#scope}

> **scope**: `string`[]

The scope assigned to the user, comma separated.
Original file line number Diff line number Diff line change
Expand Up @@ -44,18 +44,6 @@ The users organization.

***

### scope {#scope}

> **scope**: `string`[]

The scope assigned to the user, comma separated.

#### Inherited from

[`IAuthenticationUser`](IAuthenticationUser.md).[`scope`](IAuthenticationUser.md#scope)

***

### password {#password}

> **password**: `string`
Expand Down
14 changes: 2 additions & 12 deletions packages/api-auth-entity-storage-models/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,25 +7,15 @@ export * from "./models/api/IAdminUserGetResponse.js";
export * from "./models/api/IAdminUserRemoveRequest.js";
export * from "./models/api/IAdminUserUpdatePasswordRequest.js";
export * from "./models/api/IAdminUserUpdateRequest.js";
export * from "./models/api/IAuditCreateRequest.js";
export * from "./models/api/IAuditGetRequest.js";
export * from "./models/api/IAuditGetResponse.js";
export * from "./models/api/IAuditQueryRequest.js";
export * from "./models/api/IAuditQueryResponse.js";
export * from "./models/api/IAuditRemoveRequest.js";
export * from "./models/api/IAuditUpdateRequest.js";
export * from "./models/api/ILoginRequest.js";
export * from "./models/api/ILoginResponse.js";
export * from "./models/api/ILogoutRequest.js";
export * from "./models/api/IPasswordPolicyResponse.js";
export * from "./models/api/IRefreshTokenRequest.js";
export * from "./models/api/IRefreshTokenResponse.js";
export * from "./models/api/IUpdatePasswordRequest.js";
export * from "./models/authAuditEvent.js";
export * from "./models/IAuthenticationAdminComponent.js";
export * from "./models/IAuthenticationAuditComponent.js";
export * from "./models/IAuthenticationAuditEntry.js";
export * from "./models/IAuthenticationComponent.js";
export * from "./models/IAuthenticationRateActionConfig.js";
export * from "./models/IAuthenticationRateComponent.js";
export * from "./models/IAuthenticationUser.js";
export * from "./models/IAuthenticationUserSecure.js";
export * from "./models/IPasswordOptions.js";
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright 2024 IOTA Stiftung.
// SPDX-License-Identifier: Apache-2.0.
import type { IComponent } from "@3sixty/core";
import type { IPasswordOptions } from "./IPasswordOptions.js";

/**
* Contract definition for authentication component.
Expand Down Expand Up @@ -44,4 +45,10 @@ export interface IAuthenticationComponent extends IComponent {
* @returns A promise that resolves when the password has been updated.
*/
updatePassword(currentPassword: string, newPassword: string): Promise<void>;

/**
* Get the password policy used for password validation.
* @returns The password policy options.
*/
passwordPolicy(): Promise<IPasswordOptions>;
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,4 @@ export interface IAuthenticationUser {
* The users organization.
*/
organizationIdentity: string;

/**
* The scope assigned to the user, comma separated.
*/
scope: string[];
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// Copyright 2026 IOTA Stiftung.
// SPDX-License-Identifier: Apache-2.0.

/**
* Password length validation options.
*/
export interface IPasswordOptions {
/**
* The minimum password length for validation.
*/
minPasswordLength?: number;

/**
* The maximum password length for validation.
*/
maxPasswordLength?: number;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Copyright 2026 IOTA Stiftung.
// SPDX-License-Identifier: Apache-2.0.
import type { IPasswordOptions } from "../IPasswordOptions.js";

/**
* Get the password policy.
*/
export interface IPasswordPolicyResponse {
/**
* The body of the response.
*/
body: IPasswordOptions;
}
49 changes: 6 additions & 43 deletions packages/api-auth-entity-storage-rest-client/docs/examples.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,12 @@ await adminClient.create({
email: 'ops@example.org',
password: 'StrongPassword123',
userIdentity: 'did:example:ops',
organizationIdentity: 'did:example:core',
scope: ['admin']
organizationIdentity: 'did:example:core'
});

await adminClient.update({
email: 'ops@example.org',
userIdentity: 'did:example:ops:team',
scope: ['admin', 'support']
userIdentity: 'did:example:ops:team'
});

await adminClient.updatePassword('ops@example.org', 'StrongPassword124', 'StrongPassword123');
Expand All @@ -42,7 +40,7 @@ const adminClient = new EntityStorageAuthenticationAdminRestClient({
});

const byEmail = await adminClient.get('ops@example.org');
const byIdentity = await adminClient.getByIdentity('ops-team@example.org');
const byIdentity = await adminClient.getByIdentity('did:example:ops:team');
await adminClient.remove('ops@example.org');

console.log(byEmail.email); // ops@example.org
Expand All @@ -62,6 +60,9 @@ const authClient = new EntityStorageAuthenticationRestClient({

console.log(authClient.className()); // EntityStorageAuthenticationRestClient

const policy = await authClient.passwordPolicy();
console.log(policy.minPasswordLength); // 8

const loginResponse = await authClient.login('alice@example.org', 'correct-horse-battery-staple');

await authClient.updatePassword('correct-horse-battery-staple', 'correct-horse-battery-staple-2');
Expand All @@ -71,41 +72,3 @@ const refreshResponse = await authClient.refresh(loginResponse.token);
await authClient.logout(refreshResponse.token);
console.log(refreshResponse.expiry > 0); // true
```

## EntityStorageAuthenticationAuditRestClient

```typescript
import { EntityStorageAuthenticationAuditRestClient } from '@3sixty/api-auth-entity-storage-rest-client';

const auditClient = new EntityStorageAuthenticationAuditRestClient({
endpoint: 'https://api.example.org',
pathPrefix: 'v1'
});

console.log(auditClient.className()); // EntityStorageAuthenticationAuditRestClient

const auditEntryId = await auditClient.create({
event: 'login-success',
actorId: 'did:example:user:alice',
organizationId: 'did:example:org:core',
tenantId: 'did:example:tenant:alpha',
data: {
channel: 'web'
}
});

const auditResult = await auditClient.query(
{
actorId: 'did:example:user:alice',
event: 'login-success',
startDate: '2026-04-01T00:00:00.000Z',
endDate: '2026-04-30T23:59:59.999Z'
},
undefined,
25
);

console.log(auditEntryId); // /authentication/audit/018f2f67bb9d4a0caad8386f56df85ce
console.log(auditResult.entries.length); // 1
console.log(auditResult.cursor); // eyJpZCI6IjAxOGYyZjY3YmI5ZDRhMGNhYWQ4Mzg2ZjU2ZGY4NWNlIn0=
```
Loading
Loading