add pass access token in headers

This commit is contained in:
miloschwartz
2025-04-05 22:28:47 -04:00
parent 74d6b3d902
commit 6cc4bc2645
14 changed files with 333 additions and 161 deletions

View File

@@ -0,0 +1,105 @@
"use client";
import { useState } from "react";
import { Check, Copy, Info, InfoIcon } from "lucide-react";
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle
} from "@/components/ui/card";
import { Button } from "@/components/ui/button";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
import { useEnvContext } from "@app/hooks/useEnvContext";
import CopyToClipboard from "@app/components/CopyToClipboard";
import CopyTextBox from "@app/components/CopyTextBox";
interface AccessTokenSectionProps {
token: string;
tokenId: string;
resourceUrl: string;
}
export default function AccessTokenSection({
token,
tokenId,
resourceUrl
}: AccessTokenSectionProps) {
const { env } = useEnvContext();
const [copied, setCopied] = useState<string | null>(null);
const copyToClipboard = (text: string, type: string) => {
navigator.clipboard.writeText(text);
setCopied(type);
setTimeout(() => setCopied(null), 2000);
};
return (
<>
<div className="flex items-start space-x-2">
<p className="text-sm text-muted-foreground">
Your access token can be passed in two ways: as a query
parameter or in the request headers. These must be passed
from the client on every request for authenticated access.
</p>
</div>
<Tabs defaultValue="token" className="w-full mt-4">
<TabsList className="grid grid-cols-2">
<TabsTrigger value="token">Access Token</TabsTrigger>
<TabsTrigger value="usage">Usage Examples</TabsTrigger>
</TabsList>
<TabsContent value="token" className="space-y-4">
<div className="space-y-1">
<div className="font-bold">Token ID</div>
<CopyToClipboard text={tokenId} isLink={false} />
</div>
<div className="space-y-1">
<div className="font-bold">Token</div>
<CopyToClipboard text={token} isLink={false} />
</div>
</TabsContent>
<TabsContent value="usage" className="space-y-4">
<div className="space-y-2">
<h3 className="text-sm font-medium">Request Headers</h3>
<CopyTextBox
text={`${env.server.resourceAccessTokenHeadersId}: ${tokenId}
${env.server.resourceAccessTokenHeadersToken}: ${token}`}
/>
</div>
<div className="space-y-2">
<h3 className="text-sm font-medium">Query Parameter</h3>
<CopyTextBox
text={`${resourceUrl}?${env.server.resourceAccessTokenParam}=${tokenId}.${token}`}
/>
</div>
<Alert variant="neutral">
<InfoIcon className="h-4 w-4" />
<AlertTitle className="font-semibold">
Important Note
</AlertTitle>
<AlertDescription>
For security reasons, using headers is recommended
over query parameters when possible, as query
parameters may be logged in server logs or browser
history.
</AlertDescription>
</Alert>
</TabsContent>
</Tabs>
<div className="text-sm text-muted-foreground mt-4">
Keep your access token secure. Do not share it in publicly
accessible areas or client-side code.
</div>
</>
);
}

View File

@@ -4,7 +4,6 @@ import { Button } from "@app/components/ui/button";
import {
Form,
FormControl,
FormDescription,
FormField,
FormItem,
FormLabel,
@@ -20,7 +19,6 @@ import {
} from "@app/components/ui/select";
import { toast } from "@app/hooks/useToast";
import { zodResolver } from "@hookform/resolvers/zod";
import { InviteUserBody, InviteUserResponse } from "@server/routers/user";
import { AxiosResponse } from "axios";
import { useEffect, useState } from "react";
import { useForm } from "react-hook-form";
@@ -37,7 +35,6 @@ import {
CredenzaTitle
} from "@app/components/Credenza";
import { useOrgContext } from "@app/hooks/useOrgContext";
import { ListRolesResponse } from "@server/routers/role";
import { formatAxiosError } from "@app/lib/api";
import { cn } from "@app/lib/cn";
import { createApiClient } from "@app/lib/api";
@@ -58,12 +55,9 @@ import {
CommandList
} from "@app/components/ui/command";
import { CheckIcon, ChevronsUpDown } from "lucide-react";
import { register } from "module";
import { Label } from "@app/components/ui/label";
import { Checkbox } from "@app/components/ui/checkbox";
import { GenerateAccessTokenResponse } from "@server/routers/accessToken";
import {
constructDirectShareLink,
constructShareLink
} from "@app/lib/shareLinks";
import { ShareLinkRow } from "./ShareLinksTable";
@@ -73,6 +67,7 @@ import {
CollapsibleContent,
CollapsibleTrigger
} from "@app/components/ui/collapsible";
import AccessTokenSection from "./AccessTokenUsage";
type FormProps = {
open: boolean;
@@ -100,7 +95,8 @@ export default function CreateShareLinkForm({
const api = createApiClient({ env });
const [link, setLink] = useState<string | null>(null);
const [directLink, setDirectLink] = useState<string | null>(null);
const [accessTokenId, setAccessTokenId] = useState<string | null>(null);
const [accessToken, setAccessToken] = useState<string | null>(null);
const [loading, setLoading] = useState(false);
const [neverExpire, setNeverExpire] = useState(false);
@@ -226,12 +222,9 @@ export default function CreateShareLinkForm({
const token = res.data.data;
const link = constructShareLink(token.accessToken);
setLink(link);
const directLink = constructDirectShareLink(
env.server.resourceAccessTokenParam,
values.resourceUrl,
token.accessToken
);
setDirectLink(directLink);
setAccessToken(token.accessToken);
setAccessTokenId(token.accessTokenId);
const resource = resources.find(
(r) => r.resourceId === values.resourceId
@@ -515,8 +508,7 @@ export default function CreateShareLinkForm({
className="p-0 flex items-center justify-between w-full"
>
<h4 className="text-sm font-semibold">
See alternative share
links
See Access Token Usage
</h4>
<div>
<ChevronsUpDown className="h-4 w-4" />
@@ -528,26 +520,21 @@ export default function CreateShareLinkForm({
</CollapsibleTrigger>
</div>
<CollapsibleContent className="space-y-2">
{directLink && (
{accessTokenId && accessToken && (
<div className="space-y-2">
<div className="mx-auto">
<CopyTextBox
text={directLink}
wrapText={false}
<AccessTokenSection
tokenId={
accessTokenId
}
token={accessToken}
resourceUrl={
form.getValues(
"resourceUrl"
)
}
/>
</div>
<p className="text-sm text-muted-foreground">
This link does not
require visiting in a
browser to complete the
redirect. It contains
the access token
directly in the URL,
which can be useful for
sharing with clients
that do not support
redirects.
</p>
</div>
)}
</CollapsibleContent>

View File

@@ -617,7 +617,7 @@ PersistentKeepalive = 5`;
</InfoSection>
</InfoSections>
<Alert variant="default" className="">
<Alert variant="neutral" className="">
<InfoIcon className="h-4 w-4" />
<AlertTitle className="font-semibold">
Save Your Credentials
@@ -777,7 +777,7 @@ PersistentKeepalive = 5`;
<SettingsSectionBody>
<CopyTextBox text={wgConfig} />
<Alert variant="default">
<Alert variant="neutral">
<InfoIcon className="h-4 w-4" />
<AlertTitle className="font-semibold">
Save Your Credentials