Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
93 commits
Select commit Hold shift + click to select a range
f413af6
fix(facebook): return video/reel analytics instead of erroring on the…
giladresisi Jul 2, 2026
03bea3d
fix(linkedin-page): namespace step-1 internalId so page connect can't…
giladresisi Jul 23, 2026
8f92a37
fix(pinterest): read pin analytics from summary_metrics instead of li…
giladresisi Aug 6, 2026
96e46cf
fix(tiktok): correct picture_size_check_failed message and pre-check …
giladresisi Aug 11, 2026
8bcb2f5
fix(facebook): flag channels that hold a non-page token as needing re…
giladresisi Aug 12, 2026
fa69f42
fix(facebook): map (#200) permission errors to a curated message
giladresisi Aug 14, 2026
cd1e40d
fix(instagram): map (#200) permission errors to a curated message too
giladresisi Aug 18, 2026
5d3acd7
fix: reddit settings type only accepts self, link, media
giladresisi Aug 18, 2026
cf0c8ff
fix(bluesky): surface the underlying error when preparation keeps fai…
giladresisi Aug 20, 2026
3000fdd
fix(reddit): strip leading/trailing slashes from subreddit names
giladresisi Aug 20, 2026
b52cd59
fix(reddit): also strip a prefix-less r/ from subreddit names
giladresisi Aug 20, 2026
bd781c1
fix: count Threads post length in UTF-8 bytes
giladresisi Aug 23, 2026
d0c5d7c
feat(admin-stats): active orgs per post creation source
giladresisi Aug 31, 2026
3cbe20b
feat: wallet rejection
nevo-david Sep 12, 2026
cf1ff60
Merge branch 'main' into fix/facebook-video-insights
giladresisi Sep 14, 2026
3260cd3
Merge branch 'main' into admin-daily-account-stats
giladresisi Sep 14, 2026
2c2f788
feat(farcaster): migrate from SIWN to Neynar managed signers, fix log…
giladresisi Sep 14, 2026
d2246cb
fix(facebook): use META_GRAPH_API_VERSION for video_insights instead …
giladresisi Sep 14, 2026
03fab81
fix(farcaster): keep polling the signer status on network errors
giladresisi Sep 14, 2026
889f87f
fix(farcaster): throttle the public signer creation route
giladresisi Sep 14, 2026
f23ebf7
fix(farcaster): throttle the public signer status route
giladresisi Sep 14, 2026
d46c7bb
chore: sync lockfile qrcode specifiers
giladresisi Sep 14, 2026
16517c2
fix(farcaster): url-encode the base64 code in redirects
giladresisi Sep 14, 2026
6dbaadb
Merge pull request #2078 from gitroomhq/feat/farcaster-managed-signers
nevo-david Sep 15, 2026
8ce68f1
fix(farcaster): show the approval QR in a modal instead of a blank tab
giladresisi Sep 15, 2026
9b06ea2
Merge pull request #2080 from gitroomhq/fix/farcaster-qr-modal
nevo-david Sep 15, 2026
06381f0
Merge pull request #1669 from gitroomhq/fix/facebook-video-insights
giladresisi Sep 15, 2026
08de8cc
Merge pull request #1946 from gitroomhq/fix/threads-byte-length
giladresisi Sep 15, 2026
6376fd9
Merge pull request #1997 from gitroomhq/admin-daily-account-stats
giladresisi Sep 15, 2026
07ebfc7
Merge pull request #1767 from gitroomhq/fix/linkedin-page-hijacks-per…
giladresisi Sep 15, 2026
a371160
Merge pull request #1851 from gitroomhq/fix/pinterest-post-analytics
giladresisi Sep 15, 2026
a20d023
Merge pull request #1875 from gitroomhq/fix/tiktok-picture-size-message
giladresisi Sep 15, 2026
a15519a
Merge pull request #1881 from gitroomhq/fix/facebook-page-token-error…
giladresisi Sep 15, 2026
79963b5
Merge pull request #1915 from gitroomhq/fix/reddit-type-values
giladresisi Sep 15, 2026
85b42a5
Merge pull request #1929 from gitroomhq/fix/bluesky-surface-prep-error
giladresisi Sep 15, 2026
12136dc
Merge pull request #1930 from gitroomhq/fix/reddit-subreddit-slashes
giladresisi Sep 15, 2026
522a0f4
Merge remote-tracking branch 'origin/main' into fix/facebook-200-perm…
giladresisi Sep 15, 2026
73f5e2d
fix(sentry): sample traces and session replays to stay under quota
giladresisi Sep 15, 2026
0a4301e
Merge pull request #1892 from gitroomhq/fix/facebook-200-permission-m…
giladresisi Sep 16, 2026
c182d16
Merge pull request #2082 from gitroomhq/fix/sentry-usage-limits
giladresisi Sep 16, 2026
f091f54
fix(media): open the Change Bot Picture media picker as a modal
giladresisi Sep 16, 2026
0b26c98
fix(bluesky): only mark the channel disconnected on a 4xx login failure
giladresisi Sep 1, 2026
ed721b4
fix(frontend): reconnect custom-fields channels through the credentia…
giladresisi Sep 1, 2026
19f095f
fix(sentry): lower profiling even further
egelhaus Sep 16, 2026
3212ad5
Merge pull request #2084 from gitroomhq/fix/bluesky-login-transient-e…
giladresisi Sep 16, 2026
b193042
fix: resolve the webhook post by releaseId fallback
giladresisi Sep 16, 2026
7f681d4
Merge pull request #2085 from gitroomhq/fix/custom-fields-reconnect-main
giladresisi Sep 16, 2026
43cd3d5
Merge pull request #2083 from gitroomhq/fix/media-box-modal
egelhaus Sep 16, 2026
a9aced7
fix(instagram): send collaborators on carousel container instead of c…
giladresisi Jul 23, 2026
0a8c28f
fix(instagram): url-encode collaborators param
giladresisi Jul 23, 2026
1de1537
fix(instagram): strip leading @ from collaborator handles
giladresisi Aug 25, 2026
30ba635
Merge pull request #2088 from gitroomhq/feat/instagram-carousel-colla…
giladresisi Sep 16, 2026
9bb641e
Merge pull request #2087 from gitroomhq/fix/webhook-payload-lookup
giladresisi Sep 16, 2026
e2d5b9c
feat: runpod
nevo-david Sep 16, 2026
6fad985
Merge remote-tracking branch 'origin/main'
nevo-david Sep 16, 2026
914b29f
feat: replace
nevo-david Sep 16, 2026
b3cace2
fix: runpod
nevo-david Sep 16, 2026
07fd99e
ci: regenerate the lockfile instead of merging it in staging conflicts
egelhaus Sep 16, 2026
118d89c
feat: fix uploading
nevo-david Sep 16, 2026
3c0f8aa
Merge remote-tracking branch 'origin/main'
nevo-david Sep 16, 2026
920da9c
fix(oauth): grant email claims to DCR clients on verified domains
nevo-david Sep 16, 2026
83bd080
Merge pull request #2091 from gitroomhq/fix/oauth-email-claims-verifi…
nevo-david Sep 16, 2026
f22d8c8
feat(oauth): accept client_secret_basic on the token endpoint
nevo-david Sep 16, 2026
81d5a16
Merge pull request #2093 from gitroomhq/feat/oauth-client-secret-basic
nevo-david Sep 16, 2026
2a0d688
feat(mcp): separate no-DCR issuer for /mcp-oauth, DCR issuer for the …
nevo-david Sep 16, 2026
48490b8
feat(mcp): serve the ChatGPT app on /mcp-oauth-chatgpt
nevo-david Sep 16, 2026
2688501
fix(customer-modal): replace Mantine Autocomplete with native input t…
giladresisi Jul 1, 2026
6a73376
Merge pull request #2094 from gitroomhq/fix/customer-modal-react19-re…
giladresisi Sep 17, 2026
c589175
chore(deps): upgrade Mastra and CopilotKit to latest
nevo-david Sep 17, 2026
b267fbe
feat(frontend): hide the Chatbase widget while the creation modal is …
nevo-david Sep 17, 2026
facc77d
feat: x-postiz-org override and support debug endpoints on the public…
egelhaus Sep 16, 2026
671b8ea
fix: report current channel counts alongside channels connected in range
egelhaus Sep 17, 2026
b4da559
fix: exclude oauth apps from superadmin surfaces and bound the channe…
egelhaus Sep 17, 2026
7c2ac90
fix: restrict the debug endpoints to super admins
egelhaus Sep 17, 2026
a1db935
feat: add account overview debug endpoint for dispute evidence
egelhaus Sep 17, 2026
82a10ab
fix: require every privileged member of an admin org to be a superuser
egelhaus Sep 17, 2026
246c3c0
fix: authorize the super admin guard against the calling organization
egelhaus Sep 17, 2026
aee9859
fix: make channel health pick one deterministic top-level post per ch…
egelhaus Sep 17, 2026
50ba3ff
Merge branch 'chore/upgrade-mastra'
nevo-david Sep 17, 2026
6b40c64
fix(chat): run the Mastra storage migration at boot with a retry
nevo-david Sep 17, 2026
e9245ca
fix(prisma): mirror every Mastra 1.67 table and column in schema.prisma
nevo-david Sep 17, 2026
1207941
revert(chat): drop the boot-time Mastra storage init
nevo-david Sep 17, 2026
2c29ea3
feat(mcp): upload widget for uploading local files from Claude and Ch…
nevo-david Sep 18, 2026
b9e80d0
Merge pull request #2099 from gitroomhq/feat/mcp-upload-widget
nevo-david Sep 18, 2026
c6bfe13
feat: images preview
nevo-david Sep 18, 2026
1251b5a
feat: hovering and copy
nevo-david Sep 18, 2026
01219ef
Merge pull request #2096 from gitroomhq/feat/public-api-impersonate
egelhaus Sep 18, 2026
ee3eaa6
feat(staging-conflicts): stop crashing the workflow
egelhaus Sep 18, 2026
9485ca5
feat: add x-postiz-include-deleted header for the debug endpoints
egelhaus Sep 18, 2026
c3e0697
fix: require a search term and allow targeting deleted orgs with the …
egelhaus Sep 18, 2026
d539c4e
chore(sync): merge upstream main (Mastra 1.67, CopilotKit 1.72, MCP C…
JOY Sep 18, 2026
8f31206
fix(sync): leftover marker, duplicate agents key, upstream Media stat…
JOY Sep 18, 2026
0892fa2
chore(sync): merge dev (SSO worker retirement) into upstream sync branch
JOY Sep 18, 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
7 changes: 6 additions & 1 deletion apps/backend/src/api/api.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ import { IntegrationManager } from '@gitroom/nestjs-libraries/integrations/integ
import { SettingsController } from '@gitroom/backend/api/routes/settings.controller';
import { PostsController } from '@gitroom/backend/api/routes/posts.controller';
import { MediaController } from '@gitroom/backend/api/routes/media.controller';
import { MediaWidgetController } from '@gitroom/backend/api/routes/media.widget.controller';
import { UploadWidgetAuthMiddleware } from '@gitroom/backend/services/auth/upload.widget.auth.middleware';
import { UploadModule } from '@gitroom/nestjs-libraries/upload/upload.module';
import { BillingController } from '@gitroom/backend/api/routes/billing.controller';
import { NotificationsController } from '@gitroom/backend/api/routes/notifications.controller';
Expand Down Expand Up @@ -79,7 +81,7 @@ const authenticatedController = [
@Module({
imports: [UploadModule, EcosystemModule],
controllers: process.env.MCP_ONLY
? [RootController, OAuthController]
? [RootController, OAuthController, MediaWidgetController]
: [
RootController,
PaymentController,
Expand All @@ -90,6 +92,7 @@ const authenticatedController = [
EnterpriseController,
NoAuthIntegrationsController,
OAuthController,
MediaWidgetController,
...authenticatedController,
],
providers: [
Expand All @@ -101,6 +104,7 @@ const authenticatedController = [
OpenaiService,
ExtractContentService,
AuthMiddleware,
UploadWidgetAuthMiddleware,
PoliciesGuard,
PermissionsService,
CodesService,
Expand All @@ -124,5 +128,6 @@ const authenticatedController = [
export class ApiModule implements NestModule {
configure(consumer: MiddlewareConsumer) {
consumer.apply(AuthMiddleware).forRoutes(...authenticatedController);
consumer.apply(UploadWidgetAuthMiddleware).forRoutes(MediaWidgetController);
}
}
28 changes: 28 additions & 0 deletions apps/backend/src/api/routes/auth.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ import {
Query,
Req,
Res,
UseGuards,
} from '@nestjs/common';
import { Throttle } from '@nestjs/throttler';
import { ThrottlerRealIpGuard } from '@gitroom/nestjs-libraries/throttler/throttler.provider';
import { Response, Request } from 'express';

import { CreateOrgUserDto } from '@gitroom/nestjs-libraries/dtos/auth/create.org.user.dto';
Expand All @@ -24,6 +27,7 @@ import { UserAgent } from '@gitroom/nestjs-libraries/user/user.agent';
import { Provider } from '@prisma/client';
import { makeId } from '@gitroom/nestjs-libraries/services/make.is';
import * as Sentry from '@sentry/nestjs';
import { FarcasterProvider } from '@gitroom/nestjs-libraries/integrations/social/farcaster.provider';

@ApiTags('Auth')
@Controller('/auth')
Expand Down Expand Up @@ -295,6 +299,30 @@ export class AuthController {
}
}

// public and creates a signer at Neynar per call, so cap it per client
@UseGuards(ThrottlerRealIpGuard)
@Throttle({ default: { limit: 30, ttl: 3600000 } })
@Post('/farcaster/signer')
async farcasterSigner() {
try {
return await new FarcasterProvider().createSigner();
} catch (err: any) {
return { error: err.message || 'Failed to create signer' };
}
}

// the modal polls every 2s for up to 10 minutes, so leave room for that
@UseGuards(ThrottlerRealIpGuard)
@Throttle({ default: { limit: 1000, ttl: 3600000 } })
@Get('/farcaster/signer')
async farcasterSignerStatus(@Query('signerUuid') signerUuid: string) {
try {
return await new FarcasterProvider().signerStatus(signerUuid);
} catch (err: any) {
return { error: err.message || 'Failed to check signer' };
}
}

@Post('/oauth/:provider/redirect')
oauthRedirect(
@Param('provider') provider: string,
Expand Down
22 changes: 16 additions & 6 deletions apps/backend/src/api/routes/copilot.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,10 @@ import {
Query,
Param,
} from '@nestjs/common';
import OpenAI from 'openai';
import {
CopilotRuntime,
OpenAIAdapter,
copilotRuntimeNodeHttpEndpoint,
copilotRuntimeNextJSAppRouterEndpoint,
} from '@copilotkit/runtime';
import { GetOrgFromRequest } from '@gitroom/nestjs-libraries/user/org.from.request';
import { Organization } from '@prisma/client';
Expand All @@ -24,13 +22,24 @@ import { Request, Response } from 'express';
import { RequestContext } from '@mastra/core/di';
import { CheckPolicies } from '@gitroom/backend/services/auth/permissions/permissions.ability';
import { AuthorizationActions, Sections } from '@gitroom/backend/services/auth/permissions/permission.exception.class';
import OpenAI from 'openai';

export type ChannelsContext = {
integrations: string;
organization: string;
ui: string;
};

// the copilot runtime writes its own CORS headers on the response, keep them aligned with main.ts
const copilotCors = () => ({
origin: [
process.env.FRONTEND_URL,
'http://localhost:6274',
...(process.env.MAIN_URL ? [process.env.MAIN_URL] : []),
],
Comment on lines +35 to +39

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

If process.env.FRONTEND_URL is undefined, the origin array will contain undefined, which can cause issues or runtime errors in some CORS libraries. It is safer to filter out any falsy values from the origins array.

Suggested change
origin: [
process.env.FRONTEND_URL,
'http://localhost:6274',
...(process.env.MAIN_URL ? [process.env.MAIN_URL] : []),
],
origin: [
process.env.FRONTEND_URL,
'http://localhost:6274',
process.env.MAIN_URL,
].filter(Boolean) as string[],

credentials: !process.env.NOT_SECURED,
});

@Controller('/copilot')
export class CopilotController {
constructor(
Expand All @@ -54,6 +63,7 @@ export class CopilotController {

const copilotRuntimeHandler = copilotRuntimeNodeHttpEndpoint({
endpoint: '/copilot/chat',
cors: copilotCors(),
runtime: new CopilotRuntime(),
serviceAdapter: new OpenAIAdapter({
openai: openai as any,
Expand Down Expand Up @@ -82,7 +92,7 @@ export class CopilotController {
const requestContext = new RequestContext<ChannelsContext>();
requestContext.set(
'integrations',
req?.body?.variables?.properties?.integrations || []
req?.body?.body?.forwardedProps?.integrations || []
);

requestContext.set('organization', JSON.stringify(organization));
Expand All @@ -103,17 +113,17 @@ export class CopilotController {
...(process.env.OPENAI_BASE_URL ? { baseURL: process.env.OPENAI_BASE_URL } : {}),
});

const copilotRuntimeHandler = copilotRuntimeNextJSAppRouterEndpoint({
const copilotRuntimeHandler = copilotRuntimeNodeHttpEndpoint({
endpoint: '/copilot/agent',
cors: copilotCors(),
runtime,
// properties: req.body.variables.properties,
serviceAdapter: new OpenAIAdapter({
openai: openai as any,
model: process.env.OPENAI_MODEL_NAME || 'gpt-4.1',
}),
});

return copilotRuntimeHandler.handleRequest(req, res);
return copilotRuntimeHandler(req, res);
}

@Get('/credits')
Expand Down
48 changes: 28 additions & 20 deletions apps/backend/src/api/routes/media.controller.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {
BadRequestException,
Body,
Controller,
Delete,
Expand All @@ -10,7 +11,6 @@ import {
Res,
UploadedFile,
UseInterceptors,
UsePipes,
} from '@nestjs/common';
import { Request, Response } from 'express';
import { GetOrgFromRequest } from '@gitroom/nestjs-libraries/user/org.from.request';
Expand All @@ -19,7 +19,7 @@ import { MediaService } from '@gitroom/nestjs-libraries/database/prisma/media/me
import { ApiTags } from '@nestjs/swagger';
import handleR2Upload from '@gitroom/nestjs-libraries/upload/r2.uploader';
import { FileInterceptor } from '@nestjs/platform-express';
import { CustomFileValidationPipe } from '@gitroom/nestjs-libraries/upload/custom.upload.validation';
import { streamUploadOptions } from '@gitroom/nestjs-libraries/upload/multer.stream.engine';
import { SubscriptionService } from '@gitroom/nestjs-libraries/database/prisma/subscriptions/subscription.service';
import { UploadFactory } from '@gitroom/nestjs-libraries/upload/upload.factory';
import { SaveMediaInformationDto } from '@gitroom/nestjs-libraries/dtos/media/save.media.information.dto';
Expand Down Expand Up @@ -85,19 +85,19 @@ export class MediaController {
}

@Post('/upload-server')
@UseInterceptors(FileInterceptor('file'))
@UsePipes(new CustomFileValidationPipe())
@UseInterceptors(FileInterceptor('file', streamUploadOptions()))
async uploadServer(
@GetOrgFromRequest() org: Organization,
@UploadedFile() file: Express.Multer.File
) {
const originalName = file?.originalname || '';
const uploadedFile = await this.storage.uploadFile(file);
if (!file) {
throw new BadRequestException('No file provided');
}
return this._mediaService.saveFile(
org.id,
uploadedFile.originalname,
uploadedFile.path,
originalName
file.filename,
file.path,
file.originalname
);
}

Expand Down Expand Up @@ -128,26 +128,25 @@ export class MediaController {
}

@Post('/upload-simple')
@UseInterceptors(FileInterceptor('file'))
@UsePipes(new CustomFileValidationPipe())
@UseInterceptors(FileInterceptor('file', streamUploadOptions()))
async uploadSimple(
@GetOrgFromRequest() org: Organization,
@UploadedFile('file') file: Express.Multer.File,
@Body('preventSave') preventSave: string = 'false'
) {
const originalName = file.originalname;
const getFile = await this.storage.uploadFile(file);
if (!file) {
throw new BadRequestException('No file provided');
}

if (preventSave === 'true') {
const { path } = getFile;
return { path };
return { path: file.path };
}

return this._mediaService.saveFile(
org.id,
getFile.originalname,
getFile.path,
originalName
file.filename,
file.path,
file.originalname
);
}

Expand All @@ -159,15 +158,16 @@ export class MediaController {
@Param('endpoint') endpoint: string
) {
const upload = await handleR2Upload(endpoint, req, res);
if (endpoint !== 'complete-multipart-upload') {
// a rejected or failed completion has already answered with its own status
if (endpoint !== 'complete-multipart-upload' || res.headersSent) {
return upload;
}

// @ts-ignore
const name = upload.Location.split('/').pop();
const originalName = req.body?.file?.name;

const saveFile = await this._mediaService.saveFile(
const saveFile = await this._mediaService.saveUploadedFile(
org.id,
name,
// @ts-ignore
Expand All @@ -178,6 +178,14 @@ export class MediaController {
res.status(200).json({ ...upload, saved: saveFile });
}

@Get('/:id/status')
getMediaStatus(
@GetOrgFromRequest() org: Organization,
@Param('id') id: string
) {
return this._mediaService.getMediaStatus(org.id, id);
}

@Get('/')
getMedia(
@GetOrgFromRequest() org: Organization,
Expand Down
48 changes: 48 additions & 0 deletions apps/backend/src/api/routes/media.widget.controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import {
BadRequestException,
Controller,
Get,
Post,
Req,
UploadedFile,
UseInterceptors,
} from '@nestjs/common';
import { Request } from 'express';
import { ApiTags } from '@nestjs/swagger';
import { Organization } from '@prisma/client';
import { FileInterceptor } from '@nestjs/platform-express';
import { GetOrgFromRequest } from '@gitroom/nestjs-libraries/user/org.from.request';
import { MediaService } from '@gitroom/nestjs-libraries/database/prisma/media/media.service';
import { streamUploadOptions } from '@gitroom/nestjs-libraries/upload/multer.stream.engine';

@ApiTags('Media')
@Controller('/media-widget')
export class MediaWidgetController {
constructor(private _mediaService: MediaService) {}

@Post('/upload')
@UseInterceptors(FileInterceptor('file', streamUploadOptions()))
async upload(
@GetOrgFromRequest() org: Organization,
@Req() req: Request,
@UploadedFile() file: Express.Multer.File
) {
if (!file) {
throw new BadRequestException('No file provided');
}
return this._mediaService.saveUploadSessionFile(
org.id,
// @ts-ignore
req.uploadSession,
file.filename,
file.path,
file.originalname
);
}

@Get('/status')
status(@GetOrgFromRequest() org: Organization, @Req() req: Request) {
// @ts-ignore
return this._mediaService.getUploadSession(org.id, req.uploadSession);
}
}
21 changes: 18 additions & 3 deletions apps/backend/src/api/routes/oauth.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import {
import { TokenExchangeDto } from '@gitroom/nestjs-libraries/dtos/oauth/token-exchange.dto';
import { RegisterClientDto } from '@gitroom/nestjs-libraries/dtos/oauth/register-client.dto';
import { RevokeTokenDto } from '@gitroom/nestjs-libraries/dtos/oauth/revoke-token.dto';
import { extractBasicCredentials } from '@gitroom/nestjs-libraries/chat/oauth-types';

@ApiTags('OAuth')
@Controller('/oauth')
Expand Down Expand Up @@ -65,18 +66,32 @@ export class OAuthController {
}

@Post('/token')
async token(@Body() body: TokenExchangeDto) {
async token(
@Body() body: TokenExchangeDto,
@Headers('authorization') authorization?: string
) {
if (body.grant_type !== 'authorization_code') {
throw new HttpException(
{ error: 'unsupported_grant_type' },
HttpStatus.BAD_REQUEST
);
}

// client_secret_basic puts the credentials in the Authorization header,
// client_secret_post and public clients put them in the body
const basic = extractBasicCredentials(authorization);
const clientId = basic?.clientId || body.client_id;
if (!clientId) {
throw new HttpException(
{ error: 'invalid_client' },
HttpStatus.UNAUTHORIZED
);
}

return this._oauthService.exchangeCodeForToken(
body.code,
body.client_id,
body.client_secret,
clientId,
basic?.clientSecret || body.client_secret,
body.code_verifier,
body.redirect_uri
);
Expand Down
2 changes: 2 additions & 0 deletions apps/backend/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ async function start() {
'auth',
'showorg',
'impersonate',
'x-postiz-org',
'x-postiz-include-deleted',
'x-copilotkit-runtime-client-gql-version',
],
exposedHeaders: [
Expand Down
Loading
Loading