diff --git a/src/app/(dynamic-pages)/(authenticated-pages)/(user-pages)/settings/developer/ActiveApiKeyList.tsx b/src/app/(dynamic-pages)/(authenticated-pages)/(user-pages)/settings/developer/ActiveApiKeyList.tsx
deleted file mode 100644
index d1b53436..00000000
--- a/src/app/(dynamic-pages)/(authenticated-pages)/(user-pages)/settings/developer/ActiveApiKeyList.tsx
+++ /dev/null
@@ -1,73 +0,0 @@
-import { PageHeading } from '@/components/PageHeading';
-import { T } from '@/components/ui/Typography';
-import {
- Table as ShadcnTable,
- TableBody,
- TableCell,
- TableHead,
- TableHeader,
- TableRow,
-} from '@/components/ui/table';
-import { getActiveDeveloperKeys } from '@/data/user/unkey';
-import { format } from 'date-fns';
-import moment from 'moment';
-import { ConfirmRevokeTokenDialog } from './ConfirmRevokeTokenDialog';
-
-export async function ActiveApiKeyList() {
- const activeDeveloperKeys = await getActiveDeveloperKeys();
- const heading = (
-
- );
-
- if (activeDeveloperKeys.length) {
- return (
-
- {heading}
-
-
-
- API Key
- Generated On
- Expires In
- Actions
-
-
-
- {activeDeveloperKeys.map((apiKey) => {
- return (
-
-
- {apiKey.masked_key}
-
-
- {format(new Date(apiKey.created_at), 'PPP')}
-
-
-
- {apiKey.expires_at
- ? moment(apiKey.expires_at).format('LL')
- : 'No expiry'}
-
-
-
-
-
- );
- })}
-
-
-
- );
- } else {
- return (
-
- {heading}
- No active API keys.
-
- );
- }
-}
diff --git a/src/app/(dynamic-pages)/(authenticated-pages)/(user-pages)/settings/developer/ConfirmRevokeTokenDialog.tsx b/src/app/(dynamic-pages)/(authenticated-pages)/(user-pages)/settings/developer/ConfirmRevokeTokenDialog.tsx
deleted file mode 100644
index 357f43a7..00000000
--- a/src/app/(dynamic-pages)/(authenticated-pages)/(user-pages)/settings/developer/ConfirmRevokeTokenDialog.tsx
+++ /dev/null
@@ -1,85 +0,0 @@
-'use client';
-import { Button } from '@/components/ui/button';
-import {
- Dialog,
- DialogContent,
- DialogDescription,
- DialogFooter,
- DialogHeader,
- DialogTitle,
- DialogTrigger,
-} from '@/components/ui/dialog';
-import { revokeUnkeyToken } from '@/data/user/unkey';
-import { useSAToastMutation } from '@/hooks/useSAToastMutation';
-import { useState } from 'react';
-
-type Props = {
- keyId: string;
-};
-
-export const ConfirmRevokeTokenDialog = ({ keyId }: Props) => {
- const [open, setOpen] = useState(false);
- const { mutate, isLoading } = useSAToastMutation(async (keyId: string) => {
- return await revokeUnkeyToken(keyId);
- }, {
- onSettled: () => {
- setOpen(false);
- },
- loadingMessage: 'Revoking API Key...',
- successMessage: 'API Key revoked!',
- errorMessage(error) {
- try {
- if (error instanceof Error) {
- return String(error.message);
- }
- return `Failed to revoke API Key ${String(error)}`;
- } catch (_err) {
- console.warn(_err);
- return 'Failed to revoke API Key';
- }
- },
- });
-
- return (
-
- );
-};
diff --git a/src/app/(dynamic-pages)/(authenticated-pages)/(user-pages)/settings/developer/GenerateApiKey.tsx b/src/app/(dynamic-pages)/(authenticated-pages)/(user-pages)/settings/developer/GenerateApiKey.tsx
deleted file mode 100644
index 58590d7a..00000000
--- a/src/app/(dynamic-pages)/(authenticated-pages)/(user-pages)/settings/developer/GenerateApiKey.tsx
+++ /dev/null
@@ -1,70 +0,0 @@
-'use client';
-
-import { Button } from '@/components/ui/button';
-
-import { generateUnkeyToken } from '@/data/user/unkey';
-import { useSAToastMutation } from '@/hooks/useSAToastMutation';
-import { useRouter } from 'next/navigation';
-import { useState } from 'react';
-import { ViewApiKeyDialog } from './ViewApiKeyDialog';
-
-export function GenerateApiKey() {
- const router = useRouter();
- const { mutate, isLoading } = useSAToastMutation(async () => {
- return await generateUnkeyToken();
- }, {
- onSuccess: (response) => {
- if (response.status === 'success' && response.data) {
- setStep('copy_modal');
- setKeyPreview(response.data.key);
- }
- },
- errorMessage(error) {
- try {
- if (error instanceof Error) {
- return String(error.message);
- }
- return `Failed to generate API Key ${String(error)}`;
- } catch (_err) {
- console.warn(_err);
- return 'Failed to generate API Key';
- }
- },
- });
-
- const [step, setStep] = useState<'form' | 'copy_modal' | 'complete'>('form');
- const [keyPreview, setKeyPreview] = useState(null);
-
- return (
- <>
-
-
- {step === 'copy_modal' && keyPreview ? (
- {
- setStep('complete');
- router.refresh();
- }}
- apiKey={keyPreview}
- />
- ) : null}
- >
- );
-}
diff --git a/src/app/(dynamic-pages)/(authenticated-pages)/(user-pages)/settings/developer/RevokedApiKeyList.tsx b/src/app/(dynamic-pages)/(authenticated-pages)/(user-pages)/settings/developer/RevokedApiKeyList.tsx
deleted file mode 100644
index fa30b879..00000000
--- a/src/app/(dynamic-pages)/(authenticated-pages)/(user-pages)/settings/developer/RevokedApiKeyList.tsx
+++ /dev/null
@@ -1,59 +0,0 @@
-import { PageHeading } from '@/components/PageHeading';
-import {
- Table as ShadcnTable,
- TableBody,
- TableCell,
- TableHead,
- TableHeader,
- TableRow,
-} from '@/components/ui/table';
-import { getRevokedApiKeyList } from '@/data/user/unkey';
-import { format } from 'date-fns';
-
-export async function RevokedApiKeyList() {
- const revokedApiKeyList = await getRevokedApiKeyList();
-
- if (!revokedApiKeyList.length) {
- return No revoked keys
;
- }
-
- const heading = (
-
- );
-
- return (
-
- {heading}
-
-
-
-
- API Key
- Generated On
- Status
-
-
-
- {revokedApiKeyList.map((apiKey) => {
- return (
-
-
- {apiKey.masked_key}
-
-
- {format(new Date(apiKey.created_at), 'PPP')}
-
- Revoked
-
- );
- })}
-
-
-
-
- );
-}
diff --git a/src/app/(dynamic-pages)/(authenticated-pages)/(user-pages)/settings/developer/ViewApiKeyDialog.tsx b/src/app/(dynamic-pages)/(authenticated-pages)/(user-pages)/settings/developer/ViewApiKeyDialog.tsx
deleted file mode 100644
index 9b59390f..00000000
--- a/src/app/(dynamic-pages)/(authenticated-pages)/(user-pages)/settings/developer/ViewApiKeyDialog.tsx
+++ /dev/null
@@ -1,62 +0,0 @@
-'use client';
-import { Button } from '@/components/ui/button';
-import {
- Dialog,
- DialogContent,
- DialogDescription,
- DialogFooter,
- DialogHeader,
- DialogTitle,
-} from '@/components/ui/dialog';
-import { Copy, CopyCheck } from 'lucide-react';
-import { useState } from 'react';
-import { CopyToClipboard } from 'react-copy-to-clipboard';
-
-type Props = {
- apiKey: string;
- onCompleted: () => void;
-};
-
-export const ViewApiKeyDialog = ({ apiKey, onCompleted }: Props) => {
- const [open, setOpen] = useState(true);
- const [isCopied, setIsCopied] = useState(false);
-
- return (
-
- );
-};
diff --git a/src/app/(dynamic-pages)/(authenticated-pages)/(user-pages)/settings/developer/page.tsx b/src/app/(dynamic-pages)/(authenticated-pages)/(user-pages)/settings/developer/page.tsx
deleted file mode 100644
index d51a11d6..00000000
--- a/src/app/(dynamic-pages)/(authenticated-pages)/(user-pages)/settings/developer/page.tsx
+++ /dev/null
@@ -1,35 +0,0 @@
-import { PageHeading } from '@/components/PageHeading';
-import { T } from '@/components/ui/Typography';
-import { Skeleton } from '@/components/ui/skeleton';
-import { getActiveDeveloperKeyCount } from '@/data/user/unkey';
-import { Suspense } from 'react';
-import { ActiveApiKeyList } from './ActiveApiKeyList';
-import { GenerateApiKey } from './GenerateApiKey';
-import { RevokedApiKeyList } from './RevokedApiKeyList';
-
-export default async function DeveloperSettings() {
- const activeDeveloperKeyCount = await getActiveDeveloperKeyCount();
- return (
-
-
-
-
}>
-
-
- {activeDeveloperKeyCount < 3 ? (
-
- ) : (
-
You have reached API Key Limit.
- )}
-
-
}>
-
-
-
- );
-}
diff --git a/src/app/api/invitations/view/[invitationId]/route.ts b/src/app/api/invitations/view/[invitationId]/route.ts
index d4ff7d88..3addc7a6 100644
--- a/src/app/api/invitations/view/[invitationId]/route.ts
+++ b/src/app/api/invitations/view/[invitationId]/route.ts
@@ -1,5 +1,5 @@
-import { createSupabaseUserRouteHandlerClient } from '@/supabase-clients/user/createSupabaseUserRouteHandlerClient';
import { toSiteURL } from '@/utils/helpers';
+import { serverGetLoggedInUser } from '@/utils/server/serverGetLoggedInUser';
import { redirect } from 'next/navigation';
import { NextRequest, NextResponse } from 'next/server';
import { z } from 'zod';
@@ -24,12 +24,10 @@ export async function GET(
}
const { invitationId } = paramsSchema.parse(params);
- const supabaseClient = createSupabaseUserRouteHandlerClient();
- const { data, error } = await supabaseClient.auth.getSession();
- if (error) {
- throw error;
- }
- const user = data?.session?.user;
+ const user = await serverGetLoggedInUser();
+
+ // the below still won't work but at least we got rid of supabase user client on the server
+ // login form no longer exists so need to redirect to actual login but later
if (!user) {
const url = new URL(toSiteURL('/login'));
diff --git a/src/app/api/token/refresh/route.tsx b/src/app/api/token/refresh/route.tsx
deleted file mode 100644
index 8a985854..00000000
--- a/src/app/api/token/refresh/route.tsx
+++ /dev/null
@@ -1,22 +0,0 @@
-import { createSupabaseUserRouteHandlerClient } from '@/supabase-clients/user/createSupabaseUserRouteHandlerClient';
-
-export const dynamic = 'force-dynamic';
-
-export async function GET() {
- const supabase = createSupabaseUserRouteHandlerClient();
- const { data, error } = await supabase.auth.getSession();
- if (error) {
- return new Response(JSON.stringify({ error: error.message }), { status: 500, headers: { 'Content-Type': 'application/json' } });
- }
- if (!data?.session?.user) {
- return new Response(JSON.stringify({ error: 'Not logged in' }), { status: 401, headers: { 'Content-Type': 'application/json' } });
- } if (!data.session.refresh_token) {
- return new Response(JSON.stringify({ error: 'No refresh token' }), { status: 401, headers: { 'Content-Type': 'application/json' } });
- }
-
- await supabase.auth.refreshSession({
- refresh_token: data.session?.refresh_token,
- });
-
- return new Response(JSON.stringify({ message: 'Refreshed' }), { headers: { 'Content-Type': 'application/json' } });
-}
diff --git a/src/app/api/v1/me/Readme.md b/src/app/api/v1/me/Readme.md
deleted file mode 100644
index 0d74d0eb..00000000
--- a/src/app/api/v1/me/Readme.md
+++ /dev/null
@@ -1 +0,0 @@
-This is a public facing API that can be used to perform actions on behalf of a user by using Unkey.
diff --git a/src/app/api/v1/me/route.ts b/src/app/api/v1/me/route.ts
deleted file mode 100644
index 1f14e191..00000000
--- a/src/app/api/v1/me/route.ts
+++ /dev/null
@@ -1,31 +0,0 @@
-import { createSupabaseUnkeyClient } from '@/supabase-clients/unkey/createSupabaseUnkeyClient';
-import { NextRequest, NextResponse } from 'next/server';
-
-export async function GET(req: NextRequest) {
- try {
- const supabaseClient = await createSupabaseUnkeyClient(req);
- const { data, error: userError } = await supabaseClient.auth.getUser();
-
- if (userError) {
- return NextResponse.json({ error: userError.message }, { status: 500 });
- }
-
- const { user } = data;
-
- if (!user) {
- return NextResponse.json({ error: 'User not found' }, { status: 404 });
- }
-
- const responseHeaders = {
- 'Access-Control-Allow-Origin': '*',
- 'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',
- 'Access-Control-Allow-Headers': 'Content-Type, Authorization',
- };
-
- return NextResponse.json(user, {
- headers: responseHeaders,
- });
- } catch (error) {
- return new NextResponse(String(error), { status: 500 });
- }
-}
diff --git a/src/data/user/unkey.ts b/src/data/user/unkey.ts
deleted file mode 100644
index 899eb131..00000000
--- a/src/data/user/unkey.ts
+++ /dev/null
@@ -1,146 +0,0 @@
-'use server';
-import { createSupabaseUserRouteHandlerClient } from '@/supabase-clients/user/createSupabaseUserRouteHandlerClient';
-import { createSupabaseUserServerActionClient } from '@/supabase-clients/user/createSupabaseUserServerActionClient';
-import { createSupabaseUserServerComponentClient } from '@/supabase-clients/user/createSupabaseUserServerComponentClient';
-import type { SAPayload } from '@/types';
-import { serverGetLoggedInUser } from '@/utils/server/serverGetLoggedInUser';
-import axios from 'axios';
-import { revalidatePath } from 'next/cache';
-import { z } from 'zod';
-
-const generateKeyResponseSchema = z.object({
- keyId: z.string(),
- key: z.string(),
-});
-
-function maskKey(key: string): string {
- const start = key.substr(0, 3);
- const end = key.substr(-3);
- const masked = '*'.repeat(key.length - 6);
- return start + masked + end;
-}
-
-export async function generateUnkeyToken(): Promise<
- SAPayload<{ keyId: string; key: string; createdAt: string }>
-> {
- const user = await serverGetLoggedInUser();
- const supabaseClient = createSupabaseUserRouteHandlerClient();
- const response = await axios.post(
- 'https://api.unkey.dev/v1/keys',
- {
- apiId: process.env.UNKEY_API_ID,
- ownerId: user.id,
- prefix: 'st_',
- },
- {
- headers: {
- Authorization: `Bearer ${process.env.UNKEY_ROOT_KEY}`,
- 'Content-Type': 'application/json',
- },
- },
- );
- const { keyId, key } = generateKeyResponseSchema.parse(response.data);
- const { data: insertKeyResponse, error: insertKeyError } =
- await supabaseClient
- .from('user_api_keys')
- .insert({
- key_id: keyId,
- masked_key: maskKey(key),
- user_id: user.id,
- })
- .select('*')
- .single();
-
- if (insertKeyError) {
- return { status: 'error', message: insertKeyError.message };
- }
-
- return {
- status: 'success',
- data: {
- keyId,
- key,
- createdAt: insertKeyResponse.created_at,
- },
- };
-}
-
-export async function revokeUnkeyToken(
- keyId: string,
-): Promise> {
- const response = await axios.delete(
- `https://api.unkey.dev/v1/keys/${keyId}`,
- {
- headers: {
- Authorization: `Bearer ${process.env.UNKEY_ROOT_KEY}`,
- },
- },
- );
-
- const supabaseClient = createSupabaseUserServerActionClient();
-
- const { error } = await supabaseClient
- .from('user_api_keys')
- .update({
- is_revoked: true,
- })
- .eq('key_id', keyId)
- .single();
-
- if (error) {
- return { status: 'error', message: error.message };
- }
-
- revalidatePath('/', 'layout');
-
- return { status: 'success', data: { ok: true } };
-}
-
-export const getActiveDeveloperKeys = async () => {
- const user = await serverGetLoggedInUser();
- const supabaseClient = createSupabaseUserServerComponentClient();
-
- const { data, error } = await supabaseClient
- .from('user_api_keys')
- .select('*')
- .eq('user_id', user.id)
- .eq('is_revoked', false);
-
- if (error) {
- throw error;
- }
- return data;
-};
-
-export const getActiveDeveloperKeyCount = async () => {
- const user = await serverGetLoggedInUser();
- const supabaseClient = createSupabaseUserServerComponentClient();
-
- const { count, error } = await supabaseClient
- .from('user_api_keys')
- .select('*', { count: 'exact', head: true })
- .eq('user_id', user.id)
- .eq('is_revoked', false);
-
- if (error) {
- console.log(error);
- throw error;
- }
- return count ?? 0;
-};
-
-export const getRevokedApiKeyList = async () => {
- const supabaseClient = createSupabaseUserServerComponentClient();
- const user = await serverGetLoggedInUser();
-
- const { data, error } = await supabaseClient
- .from('user_api_keys')
- .select('*')
- .eq('user_id', user.id)
- .eq('is_revoked', true);
-
- if (error) {
- throw error;
- }
- return data;
-};
diff --git a/src/supabase-clients/unkey/createSupabaseUnkeyClient.ts b/src/supabase-clients/unkey/createSupabaseUnkeyClient.ts
deleted file mode 100644
index 1b744241..00000000
--- a/src/supabase-clients/unkey/createSupabaseUnkeyClient.ts
+++ /dev/null
@@ -1,60 +0,0 @@
-'use server';
-
-import { Database } from '@/lib/database.types';
-import { createClient } from '@supabase/supabase-js';
-import { verifyKey } from '@unkey/api';
-import jwt from 'jsonwebtoken';
-import { NextRequest } from 'next/server';
-import { z } from 'zod';
-
-function createJWT(userId: string) {
- const payload = {
- sub: userId,
- exp: Math.floor(Date.now() / 1000) + 60 * 60, // 1 hour expiry
- role: 'authenticated',
- aud: 'authenticated',
- iss: 'https://ultimate-demo.usenextbase.com',
- iat: Math.floor(Date.now() / 1000) - 60,
- };
-
- const token = jwt.sign(payload, process.env.SUPABASE_JWT_SECRET);
- return token;
-}
-
-const resultSchema = z.object({
- ownerId: z.string(),
- valid: z.boolean(),
- expires: z.number().optional(),
-});
-
-export async function createSupabaseUnkeyClient(req: NextRequest) {
- const authHeader = req.headers.get('Authorization');
-
- if (!authHeader || !authHeader.startsWith('Bearer ')) {
- throw new Error('Missing or invalid Authorization header');
- }
-
- const token = authHeader.split(' ')[1];
-
- const { result, error } = await verifyKey(token);
- if (error) {
- throw error;
- }
-
- const { ownerId: userId } = resultSchema.parse(result);
-
- const jwt = createJWT(userId);
- const client = createClient(
- process.env.NEXT_PUBLIC_SUPABASE_URL,
- process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY,
- {
- global: {
- headers: {
- Authorization: 'Bearer ' + jwt,
- },
- },
- },
- );
-
- return client;
-}
diff --git a/src/supabase-clients/user/createSupabaseUserRouteHandlerClient.ts b/src/supabase-clients/user/createSupabaseUserRouteHandlerClient.ts
deleted file mode 100644
index 2a2d1dcc..00000000
--- a/src/supabase-clients/user/createSupabaseUserRouteHandlerClient.ts
+++ /dev/null
@@ -1,29 +0,0 @@
-import { Database } from '@/lib/database.types';
-import { createRouteHandlerClient } from '@supabase/auth-helpers-nextjs';
-import { cookies } from 'next/headers';
-
-type createRouteHandlerClientParams = NonNullable<
- Parameters[1]
->;
-type CookieOptions = createRouteHandlerClientParams['cookieOptions'];
-
-const isDevelopment = process.env.NODE_ENV === 'development';
-
-const optionalCookieOptions: CookieOptions = {
- domain: isDevelopment ? undefined : '.digger.dev',
- secure: !isDevelopment,
- path: '/',
- sameSite: 'lax',
-};
-
-// Outstanding bug
-//https://github.com/vercel/next.js/issues/45371
-export const createSupabaseUserRouteHandlerClient = () =>
- createRouteHandlerClient(
- {
- cookies,
- },
- {
- cookieOptions: optionalCookieOptions,
- },
- );
diff --git a/src/supabase-clients/user/createSupabaseUserServerActionClient.ts b/src/supabase-clients/user/createSupabaseUserServerActionClient.ts
index 53453278..f9bf8ace 100644
--- a/src/supabase-clients/user/createSupabaseUserServerActionClient.ts
+++ b/src/supabase-clients/user/createSupabaseUserServerActionClient.ts
@@ -1,27 +1,6 @@
-import { Database } from '@/lib/database.types';
-import { createServerActionClient } from '@supabase/auth-helpers-nextjs';
-import { cookies } from 'next/headers';
+import { supabaseAdminClient } from '../admin/supabaseAdminClient';
-type createServerActionClientParams = NonNullable<
- Parameters[1]
->;
-type CookieOptions = createServerActionClientParams['cookieOptions'];
-
-const isDevelopment = process.env.NODE_ENV === 'development';
-
-const optionalCookieOptions: CookieOptions = {
- domain: isDevelopment ? undefined : '.digger.dev',
- secure: !isDevelopment,
- path: '/',
- sameSite: 'lax',
-};
-
-export const createSupabaseUserServerActionClient = () =>
- createServerActionClient(
- {
- cookies,
- },
- {
- cookieOptions: optionalCookieOptions,
- },
- );
+// this used to be a user-scoped client
+// switching to admin because we no longer use supabase auth
+// it's only used on the server so security ok
+export const createSupabaseUserServerActionClient = () => supabaseAdminClient;
diff --git a/src/supabase-clients/user/createSupabaseUserServerComponentClient.ts b/src/supabase-clients/user/createSupabaseUserServerComponentClient.ts
index 83df9eee..b7458a82 100644
--- a/src/supabase-clients/user/createSupabaseUserServerComponentClient.ts
+++ b/src/supabase-clients/user/createSupabaseUserServerComponentClient.ts
@@ -1,32 +1,7 @@
-import { Database } from '@/lib/database.types';
-import { createServerComponentClient } from '@supabase/auth-helpers-nextjs';
-import { cookies } from 'next/headers';
-
-const isDevelopment = process.env.NODE_ENV === 'development';
-
-type createServerComponentClientParams = NonNullable<
- Parameters[1]
->;
-type CookieOptions = createServerComponentClientParams['cookieOptions'];
-
-const optionalCookieOptions: CookieOptions = {
- domain: isDevelopment ? undefined : '.digger.dev',
- secure: !isDevelopment,
- path: '/',
- sameSite: 'lax',
-};
+import { supabaseAdminClient } from '../admin/supabaseAdminClient';
+// this used to be a user-scoped client
+// switching to admin because we no longer use supabase auth
+// it's only used on the server so security ok
export const createSupabaseUserServerComponentClient = () =>
- createServerComponentClient(
- {
- cookies,
- },
- {
- options: {
- global: {
- fetch,
- },
- },
- cookieOptions: optionalCookieOptions,
- },
- );
+ supabaseAdminClient;