Skip to content
Merged
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
29 changes: 29 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,35 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [v2.24.0] - 2026-09-03

### Added
- **DOS.Me Organization -> Teams Hierarchy & JIT Token Claims**:
- Integrated `teams` scope (`openid profile email organizations teams offline_access`) into OAuth authorization links.
- Added parsing for `active_org_id`, `organizations: [{ id, name, slug, role }]`, and `teams: [{ id, org_id, name, slug, role }]` claims in `OauthProvider.getUser()`.
- Added documentation for Zero-Latency JIT Token Claims and Organization/Teams hierarchy in `docs/sso-architecture.md`.
- **OpenAI-Compatible API Gateway Support**:
- Added dynamic configuration support for `OPENAI_BASE_URL`, `OPENAI_MODEL_NAME`, and `OPENAI_IMAGE_MODEL` across `OpenaiService`, `CopilotController`, `AgentGraphService`, and `AutopostService`.
- **Cross-Platform Chrome Extension Build System**:
- Added Node.js cross-platform build script (`apps/extension/build.mjs`) supporting Windows PowerShell and Linux/macOS `zip`.
- Updated Chrome Extension Manifest V3 with expanded host permissions and externally connectable domains (`*.crove.com`, `*.crove.io`, `*.dos.me`).
- **Multi-Provider Subscription Architecture**:
- Added `provider` column (`@default("stripe")`) to `Subscription` model to support multi-provider billing engines (e.g. RevenueCat).

### Fixed
- **JIT Organization Synchronization in `AuthService.checkExists()`**:
- Fixed returning users missing claim/org updates by centralizing `syncUserOrganizations()` in `checkExists()` before issuing JWT.
- Enabled canonical `orgId` inheritance during initial user/org creation in `createOrgAndUser()`.
- **Database Catalog & Schema Stability**:
- Cleaned up orphaned dynamic Mastra catalog entries from PostgreSQL.
- Optimized database connection pool strings with `connection_limit`, `pool_timeout`, and `connect_timeout`.
- **Upstream Sync**:
- Merged upstream Postiz changes including Post Workflow v1.1.1, RevenueCat subscriptions, and Seedance video provider.

### Previous Releases

## [v2.23.0] - 2026-08-27

### Added
- **Centralized DOS.Me SSO & PKCE Bridge Integration**:
- Configured Generic OAuth 2.0 client authentication pointing to `https://api.dos.me/oauth/*` (Production) and `https://beta-api.dos.me/oauth/*` (Beta).
Expand Down
4 changes: 3 additions & 1 deletion apps/backend/src/services/auth/providers.interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ export abstract class AuthProviderAbstract {
id: string;
name?: string;
picture?: string;
organizations?: Array<{ id: string; name: string; role?: 'OWNER' | 'ADMIN' | 'MEMBER' }>;
active_org_id?: string;
organizations?: Array<{ id: string; name: string; slug?: string; role?: 'OWNER' | 'ADMIN' | 'MEMBER' | 'SUPERADMIN' }>;
teams?: Array<{ id: string; org_id: string; name: string; slug: string; role?: 'LEAD' | 'MEMBER' | string }>;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

In TypeScript, unioning specific string literal types (like 'LEAD' | 'MEMBER') with the generic string type causes the entire union to collapse into string. This defeats type safety and autocompletion for the specific roles. To preserve IDE autocompletion for 'LEAD' and 'MEMBER' while still allowing any custom string, use the (string & {}) idiom.

Suggested change
teams?: Array<{ id: string; org_id: string; name: string; slug: string; role?: 'LEAD' | 'MEMBER' | string }>;
teams?: Array<{ id: string; org_id: string; name: string; slug: string; role?: 'LEAD' | 'MEMBER' | (string & {}) }>;

}> | false;
async postRegistration(
providerToken: string,
Expand Down
8 changes: 6 additions & 2 deletions apps/backend/src/services/auth/providers/oauth.provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ export class OauthProvider extends AuthProviderAbstract {
const { authUrl, clientId, frontendUrl } = this.getConfig();
const params = new URLSearchParams({
client_id: clientId,
scope: process.env.POSTIZ_OAUTH_SCOPE || 'openid profile email organizations offline_access',
scope: process.env.POSTIZ_OAUTH_SCOPE || 'openid profile email organizations teams offline_access',
response_type: 'code',
state: query?.state || 'login',
redirect_uri: `${frontendUrl}/auth`,
Expand Down Expand Up @@ -80,7 +80,9 @@ export class OauthProvider extends AuthProviderAbstract {
id: string;
name?: string;
picture?: string;
organizations?: Array<{ id: string; name: string; role?: 'OWNER' | 'ADMIN' | 'MEMBER' }>;
active_org_id?: string;
organizations?: Array<{ id: string; name: string; slug?: string; role?: 'OWNER' | 'ADMIN' | 'MEMBER' | 'SUPERADMIN' }>;
teams?: Array<{ id: string; org_id: string; name: string; slug: string; role?: 'LEAD' | 'MEMBER' | string }>;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

In TypeScript, unioning specific string literal types (like 'LEAD' | 'MEMBER') with the generic string type causes the entire union to collapse into string. This defeats type safety and autocompletion for the specific roles. To preserve IDE autocompletion for 'LEAD' and 'MEMBER' while still allowing any custom string, use the (string & {}) idiom.

Suggested change
teams?: Array<{ id: string; org_id: string; name: string; slug: string; role?: 'LEAD' | 'MEMBER' | string }>;
teams?: Array<{ id: string; org_id: string; name: string; slug: string; role?: 'LEAD' | 'MEMBER' | (string & {}) }>;

}> {
const { userInfoUrl } = this.getConfig();
const response = await fetch(`${userInfoUrl}`, {
Expand All @@ -101,7 +103,9 @@ export class OauthProvider extends AuthProviderAbstract {
id: payload.sub || payload.id,
name: payload.name || payload.full_name || payload.user_metadata?.name || payload.user_metadata?.full_name,
picture: payload.picture || payload.avatar_url || payload.user_metadata?.picture || payload.user_metadata?.avatar_url,
active_org_id: payload.active_org_id || payload.user_metadata?.active_org_id,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

To prevent potential runtime TypeError exceptions if payload or payload.user_metadata is null or undefined, use optional chaining (payload?.active_org_id and payload?.user_metadata?.active_org_id).

Suggested change
active_org_id: payload.active_org_id || payload.user_metadata?.active_org_id,
active_org_id: payload?.active_org_id || payload?.user_metadata?.active_org_id,

organizations: payload.organizations || payload.user_metadata?.organizations || [],
teams: payload.teams || payload.user_metadata?.teams || [],

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

To prevent potential runtime TypeError exceptions if payload or payload.user_metadata is null or undefined, use optional chaining (payload?.teams and payload?.user_metadata?.teams).

Suggested change
teams: payload.teams || payload.user_metadata?.teams || [],
teams: payload?.teams || payload?.user_metadata?.teams || [],

};
}
}
48 changes: 48 additions & 0 deletions docs/sso-architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,3 +118,51 @@ For all ecosystem applications (Crove Post, Crove CRM, Crove Desk, Crove Sign) c
| **Recommended Env Vars** | `CROVE_OAUTH_CLIENT_ID`<br>`CROVE_OAUTH_CLIENT_SECRET` | Standardized environment variable naming convention across the Crove ecosystem |
| **Postiz Specific Mapping** | `POSTIZ_OAUTH_CLIENT_ID=crove-postiz`<br>`POSTIZ_OAUTH_CLIENT_SECRET=<CROVE_POSTIZ_OAUTH_CLIENT_SECRET>` | Internal bridge client credentials connecting to `api.dos.me/sso/*` |

---

## 6. Organization -> Teams Hierarchy & JIT Token Claims Standard

As standardized by DOS.Me Core, all SSO identity tokens and `/sso/userinfo` endpoints now embed unified `organizations` and `teams` claims for Zero-Latency JIT Provisioning.

### Unified JWT Claims Payload:
```json
{
"sub": "7a3562bb-f529-45e0-bdfa-b73ca55ce8c8",
"email": "agent@acme.com",
"name": "Jane Doe",
"picture": "https://avatar.dos.me/jane.png",
"active_org_id": "org_987654321",
"organizations": [
{
"id": "org_987654321",
"name": "Acme Corporation",
"slug": "acme",
"role": "ADMIN"
}
],
"teams": [
{
"id": "team_11223344",
"org_id": "org_987654321",
"name": "Customer Support",
"slug": "customer-support",
"role": "LEAD"
},
{
"id": "team_55667788",
"org_id": "org_987654321",
"name": "Social Media Marketing",
"slug": "social-media",
"role": "MEMBER"
}
]
}
```

### Integration across Crove Products:
- **Crove Post (`post.crove.com`)**: Parses `organizations` for active workspace and `teams` for channel access & campaign group assignment.
- **Crove Desk (`desk.crove.com`)**: Maps `teams` to Inboxes (Support, Billing, VIP) with role `LEAD` for supervisor privileges.
- **Crove CRM (`crm.crove.com`)**: Scopes Leads, Deals, and Pipelines to the user's active `teams`.
- **Crove Sign (`sign.crove.com`)**: Authorizes document signature workflows based on team roles (`LEAD` / `ADMIN`).


Loading