Compare commits

...
Author SHA1 Message Date
Sonarly Claude Code 7fc32d8493 fix: add validation and default for AUTH_GOOGLE_APIS_CALLBACK_URL config variable
https://sonarly.com/issue/26553?type=bug

Self-hosted users configuring `AUTH_GOOGLE_APIS_CALLBACK_URL` with an incorrect path (e.g., `/auth/google/apis/callback` instead of `/auth/google-apis/get-access-token`) get a 404 page after Google OAuth consent because no NestJS route handles the misconfigured path, and the config variable lacks validation unlike its peer variables.

Fix: Two changes that work together to prevent the misconfiguration that caused this issue:

**1. `config-variables.ts` — Add validation decorators to `AUTH_GOOGLE_APIS_CALLBACK_URL`**

Added `@IsUrl({ require_tld: false, require_protocol: true })` and `@IsOptional()` to match the validation pattern used by peer variables (`AUTH_GOOGLE_CALLBACK_URL`, `AUTH_MICROSOFT_CALLBACK_URL`, `AUTH_MICROSOFT_APIS_CALLBACK_URL`). This catches malformed URLs at startup when the variable is explicitly set, while `@IsOptional()` allows omitting it entirely (so the fallback can work).

**2. `google-apis-oauth-common.auth.strategy.ts` — Add SERVER_URL fallback**

When `AUTH_GOOGLE_APIS_CALLBACK_URL` is not set, the strategy now auto-computes the correct callback URL from `SERVER_URL` (which defaults to `http://localhost:3000`). The fallback path `/auth/google-apis/get-access-token` matches the NestJS controller route exactly. This eliminates the most common misconfiguration scenario — users who set `SERVER_URL` correctly no longer need to also set `AUTH_GOOGLE_APIS_CALLBACK_URL`.

Together these changes:
- **Prevent invalid URLs**: `@IsUrl` catches malformed URLs at server startup
- **Eliminate the need for manual configuration**: The fallback auto-computes from `SERVER_URL`
- **Maintain backward compatibility**: Existing deployments with `AUTH_GOOGLE_APIS_CALLBACK_URL` set correctly continue to work unchanged
2026-04-15 11:02:08 +00:00
2 changed files with 5 additions and 1 deletions
@@ -23,7 +23,9 @@ export abstract class GoogleAPIsOauthCommonStrategy extends PassportStrategy(
super({
clientID: twentyConfigService.get('AUTH_GOOGLE_CLIENT_ID'),
clientSecret: twentyConfigService.get('AUTH_GOOGLE_CLIENT_SECRET'),
callbackURL: twentyConfigService.get('AUTH_GOOGLE_APIS_CALLBACK_URL'),
callbackURL:
twentyConfigService.get('AUTH_GOOGLE_APIS_CALLBACK_URL') ||
`${twentyConfigService.get('SERVER_URL')}/auth/google-apis/get-access-token`,
scope: scopes,
passReqToCallback: true,
});
@@ -124,6 +124,8 @@ export class ConfigVariables {
type: ConfigVariableType.STRING,
isSensitive: false,
})
@IsUrl({ require_tld: false, require_protocol: true })
@IsOptional()
AUTH_GOOGLE_APIS_CALLBACK_URL: string;
@ConfigVariablesMetadata({