diff --git a/.changeset/e2e-stabilize-fixtures.md b/.changeset/e2e-stabilize-fixtures.md new file mode 100644 index 00000000000..a845151cc84 --- /dev/null +++ b/.changeset/e2e-stabilize-fixtures.md @@ -0,0 +1,2 @@ +--- +--- diff --git a/.changeset/oauth-authorize-continue-testing-token.md b/.changeset/oauth-authorize-continue-testing-token.md new file mode 100644 index 00000000000..a845151cc84 --- /dev/null +++ b/.changeset/oauth-authorize-continue-testing-token.md @@ -0,0 +1,2 @@ +--- +--- diff --git a/integration/testUtils/setupTestingTokens.ts b/integration/testUtils/setupTestingTokens.ts index e70a50d9810..b1ac8738ad6 100644 --- a/integration/testUtils/setupTestingTokens.ts +++ b/integration/testUtils/setupTestingTokens.ts @@ -22,15 +22,21 @@ export const setupTestingTokens = async ({ await context.route( url => - (tokens.has(url.origin) && url.pathname.startsWith('/v1/')) || url.pathname.startsWith('/v1/me/oauth/consent/'), + (tokens.has(url.origin) && url.pathname.startsWith('/v1/')) || + url.pathname.startsWith('/v1/me/oauth/consent/') || + url.pathname === '/oauth/authorize/continue', async route => { - const requestUrl = new URL(route.request().url()); - const requestToken = tokens.get(requestUrl.origin); + const request = route.request(); + const requestUrl = new URL(request.url()); + const requestToken = requestUrl.pathname.startsWith('/v1/') ? tokens.get(requestUrl.origin) : undefined; if (requestToken) { requestUrl.searchParams.set('__clerk_testing_token', requestToken); } - if (route.request().method() !== 'POST' || !requestUrl.pathname.startsWith('/v1/me/oauth/consent/')) { + const redirectsToCallback = + (request.method() === 'POST' && requestUrl.pathname.startsWith('/v1/me/oauth/consent/')) || + (request.method() === 'GET' && requestUrl.pathname === '/oauth/authorize/continue'); + if (!redirectsToCallback) { if (!requestToken) { return route.fallback(); } diff --git a/integration/tests/session-tasks-sign-up.test.ts b/integration/tests/session-tasks-sign-up.test.ts index 1753a9efeed..3511ceedebb 100644 --- a/integration/tests/session-tasks-sign-up.test.ts +++ b/integration/tests/session-tasks-sign-up.test.ts @@ -1,6 +1,7 @@ import { createClerkClient } from '@clerk/backend'; import { expect, test } from '@playwright/test'; +import { environmentConfig } from '../models/environment'; import { appConfigs } from '../presets'; import { resolveInstanceKeys } from '../presets/envs'; import type { FakeUser } from '../testUtils'; @@ -79,6 +80,17 @@ testAgainstRunningApps({ withEnv: [appConfigs.envs.withSessionTasks] })( test('with sso, navigate to task on after sign-up', async ({ page, context }) => { const u = await createTestUtils({ app, page, context }); + const providerKeys = await resolveInstanceKeys('oauth-provider'); + await createTestUtils({ + app: { + ...app, + env: environmentConfig() + .setEnvVariable('public', 'CLERK_PUBLISHABLE_KEY', providerKeys.pk) + .setEnvVariable('private', 'CLERK_SECRET_KEY', providerKeys.sk), + }, + page, + context, + }); await u.po.signUp.goTo(); await u.page.getByRole('button', { name: 'E2E OAuth Provider' }).click(); @@ -89,7 +101,11 @@ testAgainstRunningApps({ withEnv: [appConfigs.envs.withSessionTasks] })( await u.po.signUp.waitForMounted(); await u.po.signUp.setEmailAddress(fakeUserForOAuth.email); await u.po.signUp.continue(); - await u.po.signUp.enterTestOtpCode(); + const [callback] = await Promise.all([ + page.waitForRequest(request => new URL(request.url()).pathname === '/v1/oauth_callback'), + u.po.signUp.enterTestOtpCode(), + ]); + expect(new URL(callback.url()).searchParams.has('__clerk_testing_token')).toBe(true); // Resolves task await u.po.signUp.waitForMounted(); diff --git a/integration/tests/testing-token.test.ts b/integration/tests/testing-token.test.ts index c230fada14c..2be97a838e1 100644 --- a/integration/tests/testing-token.test.ts +++ b/integration/tests/testing-token.test.ts @@ -13,6 +13,7 @@ test.describe('OAuth testing tokens @nextjs', () => { let appOrigin: string; let consentPosts: string[]; let consentTokens: (string | null)[]; + let authorizeTokens: (string | null)[]; test.beforeAll(async () => { app = createServer((request, response) => { @@ -37,6 +38,10 @@ test.describe('OAuth testing tokens @nextjs', () => { }); response.end('Consent accepted'); }); + } else if (url.pathname === '/oauth/authorize/continue') { + authorizeTokens.push(url.searchParams.get('__clerk_testing_token')); + response.writeHead(303, { location: url.searchParams.get('callback') || '/' }); + response.end('Authorized'); } else { response.end(JSON.stringify({ url: request.url, method: request.method })); } @@ -49,6 +54,7 @@ test.describe('OAuth testing tokens @nextjs', () => { test.beforeEach(async ({ context }) => { consentPosts = []; consentTokens = []; + authorizeTokens = []; await setupTestingTokens({ context, frontendApiOrigin: appOrigin, token: 'app-testing-token' }); }); @@ -95,6 +101,21 @@ test.describe('OAuth testing tokens @nextjs', () => { expect((await context.cookies(providerOrigin)).map(cookie => cookie.name).sort()).toEqual(['consent', 'provider']); }); + test('delivers the token on the callback when the provider skips the consent screen', async ({ page }) => { + const callback = new URL('/v1/oauth_callback?code=auth-code&state=a%2Bb%2F%3D', appOrigin); + const authorize = new URL('/oauth/authorize/continue', providerOrigin); + authorize.searchParams.set('callback', callback.toString()); + await page.goto(authorize.toString()); + + expect(authorizeTokens).toEqual([null]); + const received = JSON.parse((await page.locator('body').textContent()) || '{}'); + expect(Object.fromEntries(new URL(received.url, appOrigin).searchParams)).toEqual({ + code: 'auth-code', + state: 'a+b/=', + __clerk_testing_token: 'app-testing-token', + }); + }); + for (const [name, getCallback] of [ ['another origin', () => new URL('/v1/oauth_callback?code=auth-code', providerOrigin)], ['another path', () => new URL('/sso-callback?code=auth-code', appOrigin)], diff --git a/integration/tests/transitive-state.test.ts b/integration/tests/transitive-state.test.ts index 17d6566cd43..1026d593476 100644 --- a/integration/tests/transitive-state.test.ts +++ b/integration/tests/transitive-state.test.ts @@ -227,6 +227,7 @@ testAgainstRunningApps({ withEnv: [appConfigs.envs.withEmailCodes] })('transitiv await u.po.signIn.continue(); await u.po.signIn.setPassword(userB.password); await u.po.signIn.continue(); + await u.page.waitForFunction(userId => window.Clerk?.user?.id === userId, userBId); const pathA = '/transitive-state/sign-out'; const pathB = '/transitive-state/sign-out/sign-in';