Twenty sdk cli oauth (#18638)

<img width="1418" height="804" alt="image"
src="https://github.com/user-attachments/assets/de6c8222-6496-4a71-bc21-7e5e1269d5cb"
/>

---------

Co-authored-by: Félix Malfait <felix.malfait@gmail.com>
Co-authored-by: Félix Malfait <felix@twenty.com>
This commit is contained in:
martmull
2026-03-17 11:43:17 +01:00
committed by GitHub
parent 111debc1ce
commit 731e297147
96 changed files with 3191 additions and 2453 deletions
@@ -519,15 +519,45 @@ export class AuthService {
);
}
if (
!applicationRegistration.oAuthRedirectUris.includes(
authorizeAppInput.redirectUrl,
)
) {
throw new AuthException(
`redirectUrl mismatch for '${clientId}'`,
AuthExceptionCode.FORBIDDEN_EXCEPTION,
);
// RFC 8252 §7.3: Native apps using loopback redirect URIs may use any port.
// When a registration has no explicit redirect URIs (e.g. the seeded CLI registration),
// allow any loopback redirect URI.
const hasRegisteredRedirectUris =
applicationRegistration.oAuthRedirectUris.length > 0;
if (hasRegisteredRedirectUris) {
if (
!applicationRegistration.oAuthRedirectUris.includes(
authorizeAppInput.redirectUrl,
)
) {
throw new AuthException(
`redirectUrl mismatch for '${clientId}'`,
AuthExceptionCode.FORBIDDEN_EXCEPTION,
);
}
} else {
let redirectUrl: URL;
try {
redirectUrl = new URL(authorizeAppInput.redirectUrl);
} catch {
throw new AuthException(
`Invalid redirectUrl for '${clientId}'`,
AuthExceptionCode.FORBIDDEN_EXCEPTION,
);
}
const isLoopback =
redirectUrl.hostname === 'localhost' ||
redirectUrl.hostname === '127.0.0.1';
if (!isLoopback) {
throw new AuthException(
`redirectUrl mismatch for '${clientId}'`,
AuthExceptionCode.FORBIDDEN_EXCEPTION,
);
}
}
// Validate requested scopes are a subset of the registration's allowed scopes
@@ -76,9 +76,6 @@ const createSignInUpServiceForTests = () => {
{
emitCustomBatchEvent: jest.fn(),
} as any,
{
getHttpClient: jest.fn(),
} as any,
mockTwentyConfigService as any,
{
generateSubdomain: jest.fn(),
@@ -33,7 +33,6 @@ import { FileCorePictureService } from 'src/engine/core-modules/file/file-core-p
import { MetricsService } from 'src/engine/core-modules/metrics/metrics.service';
import { MetricsKeys } from 'src/engine/core-modules/metrics/types/metrics-keys.type';
import { OnboardingService } from 'src/engine/core-modules/onboarding/onboarding.service';
import { SecureHttpClientService } from 'src/engine/core-modules/secure-http-client/secure-http-client.service';
import { TelemetryEventType } from 'src/engine/core-modules/telemetry/telemetry-event.type';
import { TwentyConfigService } from 'src/engine/core-modules/twenty-config/twenty-config.service';
import { UserWorkspaceService } from 'src/engine/core-modules/user-workspace/user-workspace.service';
@@ -59,7 +58,6 @@ export class SignInUpService {
private readonly userWorkspaceService: UserWorkspaceService,
private readonly onboardingService: OnboardingService,
private readonly workspaceEventEmitter: WorkspaceEventEmitter,
private readonly secureHttpClientService: SecureHttpClientService,
private readonly twentyConfigService: TwentyConfigService,
private readonly subdomainManagerService: SubdomainManagerService,
private readonly userService: UserService,