Skip to content
Closed
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
2 changes: 2 additions & 0 deletions .changeset/e2e-stabilize-fixtures.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
---
---
2 changes: 2 additions & 0 deletions .changeset/oauth-authorize-continue-testing-token.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
---
---
14 changes: 10 additions & 4 deletions integration/testUtils/setupTestingTokens.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
Expand Down
18 changes: 17 additions & 1 deletion integration/tests/session-tasks-sign-up.test.ts
Original file line number Diff line number Diff line change
@@ -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';
Expand Down Expand Up @@ -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();
Expand All @@ -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();
Expand Down
21 changes: 21 additions & 0 deletions integration/tests/testing-token.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
let appOrigin: string;
let consentPosts: string[];
let consentTokens: (string | null)[];
let authorizeTokens: (string | null)[];

test.beforeAll(async () => {
app = createServer((request, response) => {
Expand All @@ -37,6 +38,10 @@
});
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') || '/' });

Check warning

Code scanning / CodeQL

Server-side URL redirect Medium test

Untrusted URL redirection depends on a
user-provided value
.
response.end('Authorized');
} else {
response.end(JSON.stringify({ url: request.url, method: request.method }));
}
Expand All @@ -49,6 +54,7 @@
test.beforeEach(async ({ context }) => {
consentPosts = [];
consentTokens = [];
authorizeTokens = [];
await setupTestingTokens({ context, frontendApiOrigin: appOrigin, token: 'app-testing-token' });
});

Expand Down Expand Up @@ -95,6 +101,21 @@
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)],
Expand Down
1 change: 1 addition & 0 deletions integration/tests/transitive-state.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down
Loading