Skip to content

Commit 938418f

Browse files
authored
Merge pull request #2 from RooCodeInc/jr/extension-auth
2 parents 6feaf74 + e062feb commit 938418f

File tree

5 files changed

+119
-0
lines changed

5 files changed

+119
-0
lines changed

.env

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
BILLING_PLAN_ENV=dev
22

3+
VSCODE_EXTENSION_BASE_URL=vscode://RooVeterinaryInc.roo-cline
4+
35
# Clerk
46
# https://clerk.com/docs/deployments/clerk-environment-variables#sign-in-and-sign-up-redirects
57
NEXT_PUBLIC_CLERK_SIGN_IN_URL=/sign-in
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { getSignInToken } from '@/lib/server/clerk';
2+
import { Env } from '@/lib/server/env';
3+
import { auth } from '@clerk/nextjs/server';
4+
import { redirect } from 'next/navigation';
5+
import { type NextRequest } from 'next/server';
6+
7+
export async function GET(request: NextRequest) {
8+
const authObj = await auth();
9+
const userId = authObj.userId;
10+
const state = request.nextUrl.searchParams.get('state') || '';
11+
12+
if (!userId) {
13+
return new Response('Unauthorized', { status: 401 });
14+
}
15+
16+
const signInToken = await getSignInToken(authObj.userId);
17+
if (!signInToken) {
18+
throw new Error("couldn't sign in");
19+
}
20+
21+
const url = new URL(`${Env.VSCODE_EXTENSION_BASE_URL}/auth/clerk/callback`);
22+
url.searchParams.append('state', state);
23+
url.searchParams.append('code', signInToken);
24+
redirect(url.href);
25+
}

src/app/api/ping/route.ts

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import { auth } from '@clerk/nextjs/server';
2+
import { NextResponse } from 'next/server';
3+
4+
import { logger } from '@/lib/server/logger';
5+
6+
/**
7+
* API endpoint for testing Clerk authentication
8+
* Verifies/parses JWT and logs authenticated user information
9+
*/
10+
export async function GET() {
11+
const authObj = await auth();
12+
13+
// If not authenticated
14+
if (!authObj.userId) {
15+
return NextResponse.json(
16+
{ error: 'Unauthorized request' },
17+
{ status: 401 },
18+
);
19+
}
20+
21+
// Get the JWT token
22+
const token = await authObj.getToken();
23+
24+
// Extract user information from the auth object
25+
// Only include properties that exist on the auth object
26+
const userInfo = {
27+
userId: authObj.userId,
28+
sessionId: authObj.sessionId,
29+
orgId: authObj.orgId,
30+
orgRole: authObj.orgRole,
31+
// Note: To get additional user data like email, firstName, lastName,
32+
// you would need to use Clerk's methods like clerkClient.users.getUser()
33+
};
34+
35+
// Log the user information
36+
logger.info({
37+
event: 'ping_endpoint_accessed',
38+
userInfo: {
39+
userId: authObj.userId,
40+
sessionId: authObj.sessionId,
41+
orgId: authObj.orgId,
42+
orgRole: authObj.orgRole,
43+
},
44+
hasToken: !!token, // Just log if token exists, not the actual token for security
45+
});
46+
47+
// Return the user information
48+
return NextResponse.json({
49+
authenticated: true,
50+
userInfo,
51+
});
52+
}

src/lib/server/clerk.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import { Env } from './env';
2+
import { logger } from './logger';
3+
4+
export async function getSignInToken(
5+
userId: string,
6+
): Promise<string | undefined> {
7+
const response = await fetch('https://api.clerk.com/v1/sign_in_tokens', {
8+
method: 'POST',
9+
headers: {
10+
Authorization: `Bearer ${Env.CLERK_SECRET_KEY}`,
11+
'Content-Type': 'application/json',
12+
},
13+
body: JSON.stringify({
14+
user_id: userId,
15+
// Default expiration is 30 days (2592000 seconds)
16+
}),
17+
});
18+
19+
if (!response.ok) {
20+
const errorData = await response.json();
21+
logger.error({
22+
event: 'sign_in_token_creation_failed',
23+
error: errorData,
24+
userId,
25+
});
26+
27+
throw new Error("Failed to create sign-in token");
28+
}
29+
30+
const data = await response.json();
31+
32+
logger.info({
33+
event: 'sign_in_token_created',
34+
userId,
35+
});
36+
37+
return data.token;
38+
}

src/lib/server/env.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ export const Env = createEnv({
99
STRIPE_SECRET_KEY: z.string().min(1),
1010
STRIPE_WEBHOOK_SECRET: z.string().min(1),
1111
BILLING_PLAN_ENV: z.enum(['dev', 'test', 'prod']),
12+
VSCODE_EXTENSION_BASE_URL: z.string().min(1),
1213
},
1314
client: {
1415
NEXT_PUBLIC_APP_URL: z.string().optional(),
@@ -32,6 +33,7 @@ export const Env = createEnv({
3233
STRIPE_SECRET_KEY: process.env.STRIPE_SECRET_KEY,
3334
STRIPE_WEBHOOK_SECRET: process.env.STRIPE_WEBHOOK_SECRET,
3435
BILLING_PLAN_ENV: process.env.BILLING_PLAN_ENV,
36+
VSCODE_EXTENSION_BASE_URL: process.env.VSCODE_EXTENSION_BASE_URL,
3537
NEXT_PUBLIC_APP_URL: process.env.NEXT_PUBLIC_APP_URL,
3638
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY:
3739
process.env.NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY,

0 commit comments

Comments
 (0)