diff --git a/dashboard/bun.lockb b/dashboard/bun.lockb index 4148b6f..457965a 100755 Binary files a/dashboard/bun.lockb and b/dashboard/bun.lockb differ diff --git a/dashboard/package.json b/dashboard/package.json index 589ca60..9641b8b 100644 --- a/dashboard/package.json +++ b/dashboard/package.json @@ -14,15 +14,13 @@ "@ory/integrations": "^1.1.5", "@radix-ui/react-alert-dialog": "^1.0.5", "@radix-ui/react-checkbox": "^1.0.4", - "@radix-ui/react-dialog": "^1.1.6", + "@radix-ui/react-dialog": "^1.1.2", "@radix-ui/react-dropdown-menu": "^2.0.6", "@radix-ui/react-hover-card": "^1.1.2", "@radix-ui/react-label": "^2.0.2", "@radix-ui/react-scroll-area": "^1.0.5", - "@radix-ui/react-select": "^2.1.6", "@radix-ui/react-separator": "^1.1.0", "@radix-ui/react-slot": "^1.1.1", - "@radix-ui/react-switch": "^1.1.3", "@radix-ui/react-tabs": "^1.1.1", "@radix-ui/react-tooltip": "^1.1.4", "@serwist/next": "^9.0.0-preview.21", @@ -32,7 +30,6 @@ "@tanstack/react-table": "^8.20.5", "class-variance-authority": "^0.7.1", "clsx": "^2.1.0", - "cmdk": "1.0.0", "dotenv": "^16.4.7", "drizzle-orm": "^0.38.3", "lucide-react": "^0.462.0", diff --git a/dashboard/src/app/(inside)/client/create/page.tsx b/dashboard/src/app/(inside)/client/create/page.tsx deleted file mode 100644 index 3aa3c9a..0000000 --- a/dashboard/src/app/(inside)/client/create/page.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import { CreateClientForm } from '@/components/forms/client-form'; -import { createClient } from '@/lib/action/client'; -import { checkPermission, requireSession } from '@/lib/action/authentication'; -import { permission, relation } from '@/lib/permission'; -import { redirect } from 'next/navigation'; - -export default async function CreateClientPage() { - - const session = await requireSession(); - const identityId = session.identity!.id; - - const pmCreateClient = await checkPermission(permission.client.it, relation.create, identityId); - if (!pmCreateClient) { - return redirect('/client'); - } - - return ( -
-
-

Create OAuth2 Client

-

- Configure your new OAuth2 Client. -

-
- -
- ); -} \ No newline at end of file diff --git a/dashboard/src/app/(inside)/client/page.tsx b/dashboard/src/app/(inside)/client/page.tsx index 42e0092..0d3f5a3 100644 --- a/dashboard/src/app/(inside)/client/page.tsx +++ b/dashboard/src/app/(inside)/client/page.tsx @@ -1,9 +1,4 @@ import { getOAuth2Api } from '@/ory/sdk/server'; -import { Button } from '@/components/ui/button'; -import Link from 'next/link'; -import { checkPermission, requireSession } from '@/lib/action/authentication'; -import { permission, relation } from '@/lib/permission'; -import InsufficientPermission from '@/components/insufficient-permission'; import { ClientDataTable } from '@/app/(inside)/client/data-table'; export interface FetchClientPageProps { @@ -34,12 +29,6 @@ function parseTokens(link: string) { async function fetchClientPage({ pageSize, pageToken }: FetchClientPageProps) { 'use server'; - const session = await requireSession(); - const allowed = await checkPermission(permission.client.it, relation.access, session.identity!.id); - if (!allowed) { - throw Error('Unauthorised'); - } - const oAuth2Api = await getOAuth2Api(); const response = await oAuth2Api.listOAuth2Clients({ pageSize: pageSize, @@ -54,49 +43,24 @@ async function fetchClientPage({ pageSize, pageToken }: FetchClientPageProps) { export default async function ListClientPage() { - const session = await requireSession(); - const identityId = session.identity!.id; - - const pmAccessClient = await checkPermission(permission.client.it, relation.access, identityId); - const pmCreateClient = await checkPermission(permission.client.it, relation.create, identityId); - let pageSize = 100; let pageToken: string = '00000000-0000-0000-0000-000000000000'; - const initialFetch = pmAccessClient && await fetchClientPage({ pageSize, pageToken }); + const initialFetch = await fetchClientPage({ pageSize, pageToken }); return (
-
+

OAuth2 Clients

See and manage all OAuth2 clients registered with your Ory Hydra instance

- { - pmCreateClient && ( - - ) - }
- { - pmAccessClient ? - ( - initialFetch && - ) - : - - } +
); } diff --git a/dashboard/src/app/globals.css b/dashboard/src/app/globals.css index 65bc799..262da57 100644 --- a/dashboard/src/app/globals.css +++ b/dashboard/src/app/globals.css @@ -75,15 +75,4 @@ body { @apply bg-sidebar text-foreground; } -} - - -@layer base { - * { - @apply border-border outline-ring/50; - } - - body { - @apply bg-background text-foreground; - } } \ No newline at end of file diff --git a/dashboard/src/components/forms/client-form.tsx b/dashboard/src/components/forms/client-form.tsx deleted file mode 100644 index 0ca84b6..0000000 --- a/dashboard/src/components/forms/client-form.tsx +++ /dev/null @@ -1,588 +0,0 @@ -'use client'; - -import { z } from 'zod'; -import { clientFormSchema } from '@/lib/forms/client-form'; -import { useForm } from 'react-hook-form'; -import { zodResolver } from '@hookform/resolvers/zod'; -import { Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage } from '@/components/ui/form'; -import { Input } from '@/components/ui/input'; -import { Button } from '@/components/ui/button'; -import { useState } from 'react'; -import { OAuth2Client } from '@ory/client'; -import { AxiosResponse } from 'axios'; -import { AlertDialog, AlertDialogContent, AlertDialogHeader, AlertDialogTitle } from '@/components/ui/alert-dialog'; -import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; -import { useRouter } from 'next/navigation'; -import { Minus } from 'lucide-react'; -import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; -import { Switch } from '@/components/ui/switch'; -import Link from 'next/link'; - -interface CreateClientFormProps { - action: (data: z.infer) => Promise>; -} - -export function CreateClientForm({ action }: CreateClientFormProps) { - - const router = useRouter(); - - const [redirectUris, setRedirectUris] = useState(['']); - const [postLogoutRedirectUris, setPostLogoutRedirectUris] = useState(['']); - - const form = useForm>({ - resolver: zodResolver(clientFormSchema), - defaultValues: { - client_name: '', - scope: '', - redirect_uris: [''], - skip: false, - logo_uri: '', - policy_uri: '', - tos_uri: '', - owner: '', - }, - }); - - const [successDialogOpen, setSuccessDialogOpen] = useState(false); - const [createdClient, setCreatedClient] = useState(); - const handleSubmit = async (data: z.infer) => { - await action(data) - .then((response) => { - console.log(response); - return response.data; - }) - .then((client) => { - setCreatedClient(client); - setSuccessDialogOpen(true); - }) - .catch((error) => { - console.error(error); - }); - }; - - const addRedirectUri = () => { - setRedirectUris([...redirectUris, '']); - }; - - const addPostLogoutRedirectUri = () => { - setPostLogoutRedirectUris([...postLogoutRedirectUris, '']); - }; - - const removeRedirectUri = (index: number) => { - const updatedRedirectUris = redirectUris.filter((_, i) => i !== index); - setRedirectUris(updatedRedirectUris); - form.setValue('redirect_uris', updatedRedirectUris); - }; - - const removePostLogoutRedirectUri = (index: number) => { - const updatedPostLogoutRedirectUris = postLogoutRedirectUris.filter((_, i) => i !== index); - setPostLogoutRedirectUris(postLogoutRedirectUris); - form.setValue('post_logout_redirect_uris', updatedPostLogoutRedirectUris); - }; - - const handleInputChange = (index: number, event: any) => { - const updatedRedirectUris = [...redirectUris]; - updatedRedirectUris[index] = event.target.value; - setRedirectUris(updatedRedirectUris); - form.setValue('redirect_uris', updatedRedirectUris); - }; - - const handlePostLogoutInputChange = (index: number, event: any) => { - const updatedPostLogoutRedirectUris = [...postLogoutRedirectUris]; - updatedPostLogoutRedirectUris[index] = event.target.value; - setPostLogoutRedirectUris(updatedPostLogoutRedirectUris); - form.setValue('post_logout_redirect_uris', updatedPostLogoutRedirectUris); - }; - - return ( - <> - { - createdClient && ( - setSuccessDialogOpen(false)}> - - - Client created - - Your client was created successfully. Make sure to safe the client secret! - - - - ) - } -
- - - - - - Essentials - - - - ( - - Client Name - - The human-readable name of the client to be presented to the end-user during - authorization. - - - - - - - )} - /> - ( - - Scopes - - Scope is a string containing a space-separated list of scope values (as - described in Section 3.3 of OAuth 2.0 [RFC6749]) that the client can use - when requesting access tokens. - - - - - - - )} - /> - {redirectUris.map((uri, index) => ( -
- - Redirect - URI {index + 1} - -
- handleInputChange(index, event)} - /> - {redirectUris.length > 1 && ( - - )} -
-
- {form.formState.errors?.redirect_uris && form.formState.errors.redirect_uris[index] && ( - {form.formState.errors.redirect_uris[index].message} - )} -
-
- ))} - - -
-
- - - - - Consent Screen - - - - ( - -
- - Skip consent - - - Whether or not the consent screen is skipped for this client - -
- - - -
- )} - /> - { - !form.getValues('skip') && ( - <> - ( - - Logo URI - - A URL string referencing the client's logo. - - - - - - - )} - /> - - ( - - Policy URI - - A URL string pointing to a human-readable privacy policy - document - for the client that describes how the deployment organization - collects, uses, retains, and discloses personal data. - - - - - - - )} - /> - - ( - - Terms URI - - A URL string pointing to a human-readable terms of service - document for the client that describes a contractual - relationship between the end-user and the client that the - end-user accepts when authorizing the client. - - - - - - - )} - /> - - ( - - Owner - - Owner is a string identifying the owner of the OAuth 2.0 Client. - - - - - - - )} - /> - - ) - } -
-
- - - - - Supported OAuth2 flows - - - Configure allowed grant types and response types for this OAuth2 Client. - - - - ( - - Grant types - - {/* TODO: add multiselect component */} - - - - - )} - /> - ( - - Response types - - {/* TODO: add multiselect component */} - - - - - )} - /> - - Access token type - - - - - - - - - - - - Client authentication mechanism - - - Set the client authentication method for the token endpoint. By default the client - credentials must be sent in the body of an HTTP POST. This option can also specify for - sending the credentials encoded in the HTTP Authorization header or by using JSON Web - Tokens. Specify none for public clients (native apps, mobile apps) which can not have - secrets. - - - - ( - - Authentication method - - - - )} - /> - - - - - - - OpenID Connect logout - - - Get more information about using front and backchannels here  - . - - - - ( - -
- - Frontchannel Logout Session Required - - - Boolean value specifying whether the Relay Party (RP) requires that - issuer and session ID query parameters be included to identify the RP - session with the OpenID provider (OP) when the Frontchannel Logout URI - is used. The default value is false. - -
- - - -
- )} - /> - ( - - Frontchannel Logout URI - - URL that will cause the Relying Party (RP) to log itself out when rendered - in an iframe by the OpenID provider (OP). An issuer query parameter and a - session ID query parameter MAY be included by the OpenID provider (OP) to - enable the Relying Party (RP) to validate the request and to determine which - of the potentially multiple sessions is to be logged out; if either is - included, both MUST be. - - - - - - - )} - /> - ( - -
- - Backchannel Logout Session Required - - - Boolean value specifying whether the Relying Party (RP) requires that a - session ID Claim be included in the Logout Token to identify the Relying - Party session with the OpenID provider (OP) when the Backchannel Logout - URI is used. If omitted, the default value is false. - -
- - - -
- )} - /> - ( - - Backchannel Logout URI - - URL that will cause the Relying Party (RP) to log itself out when rendered - in an iframe by the OpenID provider (OP). An issuer query parameter and a - session ID query parameter MAY be included by the OpenID provider (OP) to - enable the Relying Party (RP) to validate the request and to determine which - of the potentially multiple sessions is to be logged out; if either is - included, both MUST be. - - - - - - - )} - /> - ( - -
- - Skip logout consent - - - Boolean value specifying whether the additional logout consent screen - should be skipped. - -
- - - -
- )} - /> - {postLogoutRedirectUris.map((uri, index) => ( -
- - - Post Logout Redirect URI {index + 1} - -
- handlePostLogoutInputChange(index, event)} - /> - {postLogoutRedirectUris.length > 1 && ( - - )} -
-
- {form.formState.errors?.post_logout_redirect_uris && form.formState.errors.post_logout_redirect_uris[index] && ( - {form.formState.errors.post_logout_redirect_uris[index].message} - )} -
-
- ))} - - -
-
- -
- - -
-
- - - ); -} diff --git a/dashboard/src/components/ui/card.tsx b/dashboard/src/components/ui/card.tsx index 22ccc98..3c69472 100644 --- a/dashboard/src/components/ui/card.tsx +++ b/dashboard/src/components/ui/card.tsx @@ -23,7 +23,7 @@ const CardHeader = React.forwardRef< >(({ className, ...props }, ref) => (
)); @@ -60,7 +60,7 @@ const CardContent = React.forwardRef< HTMLDivElement, React.HTMLAttributes >(({ className, ...props }, ref) => ( -
+
)); CardContent.displayName = 'CardContent'; @@ -70,7 +70,7 @@ const CardFooter = React.forwardRef< >(({ className, ...props }, ref) => (
)); diff --git a/dashboard/src/components/ui/command.tsx b/dashboard/src/components/ui/command.tsx deleted file mode 100644 index f485776..0000000 --- a/dashboard/src/components/ui/command.tsx +++ /dev/null @@ -1,154 +0,0 @@ -'use client'; - -import * as React from 'react'; -import { type DialogProps } from '@radix-ui/react-dialog'; -import { Command as CommandPrimitive } from 'cmdk'; -import { Search } from 'lucide-react'; - -import { cn } from '@/lib/utils'; -import { Dialog, DialogContent } from '@/components/ui/dialog'; - -const Command = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)); -Command.displayName = CommandPrimitive.displayName; - -const CommandDialog = ({ children, ...props }: DialogProps) => { - return ( - - - - {children} - - - - ); -}; - -const CommandInput = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( -
- - -
-)); - -CommandInput.displayName = CommandPrimitive.Input.displayName; - -const CommandList = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)); - -CommandList.displayName = CommandPrimitive.List.displayName; - -const CommandEmpty = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->((props, ref) => ( - -)); - -CommandEmpty.displayName = CommandPrimitive.Empty.displayName; - -const CommandGroup = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)); - -CommandGroup.displayName = CommandPrimitive.Group.displayName; - -const CommandSeparator = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)); -CommandSeparator.displayName = CommandPrimitive.Separator.displayName; - -const CommandItem = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)); - -CommandItem.displayName = CommandPrimitive.Item.displayName; - -const CommandShortcut = ({ - className, - ...props - }: React.HTMLAttributes) => { - return ( - - ); -}; -CommandShortcut.displayName = 'CommandShortcut'; - -export { - Command, - CommandDialog, - CommandInput, - CommandList, - CommandEmpty, - CommandGroup, - CommandItem, - CommandShortcut, - CommandSeparator, -}; diff --git a/dashboard/src/components/ui/dialog.tsx b/dashboard/src/components/ui/dialog.tsx deleted file mode 100644 index c7b4160..0000000 --- a/dashboard/src/components/ui/dialog.tsx +++ /dev/null @@ -1,123 +0,0 @@ -'use client'; - -import * as React from 'react'; -import * as DialogPrimitive from '@radix-ui/react-dialog'; -import { X } from 'lucide-react'; - -import { cn } from '@/lib/utils'; - -const Dialog = DialogPrimitive.Root; - -const DialogTrigger = DialogPrimitive.Trigger; - -const DialogPortal = DialogPrimitive.Portal; - -const DialogClose = DialogPrimitive.Close; - -const DialogOverlay = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)); -DialogOverlay.displayName = DialogPrimitive.Overlay.displayName; - -const DialogContent = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, children, ...props }, ref) => ( - - - - {children} - - - Close - - - -)); -DialogContent.displayName = DialogPrimitive.Content.displayName; - -const DialogHeader = ({ - className, - ...props - }: React.HTMLAttributes) => ( -
-); -DialogHeader.displayName = 'DialogHeader'; - -const DialogFooter = ({ - className, - ...props - }: React.HTMLAttributes) => ( -
-); -DialogFooter.displayName = 'DialogFooter'; - -const DialogTitle = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)); -DialogTitle.displayName = DialogPrimitive.Title.displayName; - -const DialogDescription = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)); -DialogDescription.displayName = DialogPrimitive.Description.displayName; - -export { - Dialog, - DialogPortal, - DialogOverlay, - DialogClose, - DialogTrigger, - DialogContent, - DialogHeader, - DialogFooter, - DialogTitle, - DialogDescription, -}; diff --git a/dashboard/src/components/ui/multi-select.tsx b/dashboard/src/components/ui/multi-select.tsx deleted file mode 100644 index 266eea7..0000000 --- a/dashboard/src/components/ui/multi-select.tsx +++ /dev/null @@ -1,129 +0,0 @@ -'use client'; - -import * as React from 'react'; -import { X } from 'lucide-react'; - -import { Badge } from '@/components/ui/badge'; -import { Command, CommandGroup, CommandItem, CommandList } from '@/components/ui/command'; -import { Command as CommandPrimitive } from 'cmdk'; - -type MultiSelectItem = Record<'value' | 'label', string>; - -interface MultiSelectProps { - items: MultiSelectItem[]; - placeholder?: string; -} - -// Credits: https://github.com/mxkaske/mxkaske.dev/blob/main/components/craft/fancy-multi-select.tsx -export function MultiSelect({ items, placeholder }: MultiSelectProps) { - const inputRef = React.useRef(null); - const [open, setOpen] = React.useState(false); - const [selected, setSelected] = React.useState([]); - const [inputValue, setInputValue] = React.useState(''); - - const handleUnselect = React.useCallback((item: MultiSelectItem) => { - setSelected((prev) => prev.filter((s) => s.value !== item.value)); - }, []); - - const handleKeyDown = React.useCallback( - (e: React.KeyboardEvent) => { - const input = inputRef.current; - if (input) { - if (e.key === 'Delete' || e.key === 'Backspace') { - if (input.value === '') { - setSelected((prev) => { - const newSelected = [...prev]; - newSelected.pop(); - return newSelected; - }); - } - } - // This is not a default behaviour of the field - if (e.key === 'Escape') { - input.blur(); - } - } - }, - [], - ); - - const selectables = items.filter( - (item) => !selected.includes(item), - ); - - console.log(selectables, selected, inputValue); - - return ( - -
-
- {selected.map((item) => { - return ( - - {item.label} - - - ); - })} - {/* Avoid having the "Search" Icon */} - setOpen(false)} - onFocus={() => setOpen(true)} - placeholder={placeholder ?? 'Select an item...'} - className="ml-2 flex-1 bg-transparent outline-none placeholder:text-muted-foreground" - /> -
-
-
- - {open && selectables.length > 0 ? ( -
- - {selectables.map((item) => { - return ( - { - e.preventDefault(); - e.stopPropagation(); - }} - onSelect={(value) => { - setInputValue(''); - setSelected((prev) => [...prev, item]); - }} - className={'cursor-pointer'} - > - {item.label} - - ); - })} - -
- ) : null} -
-
-
- ); -} \ No newline at end of file diff --git a/dashboard/src/components/ui/select.tsx b/dashboard/src/components/ui/select.tsx deleted file mode 100644 index ddd77ac..0000000 --- a/dashboard/src/components/ui/select.tsx +++ /dev/null @@ -1,160 +0,0 @@ -'use client'; - -import * as React from 'react'; -import * as SelectPrimitive from '@radix-ui/react-select'; -import { Check, ChevronDown, ChevronUp } from 'lucide-react'; - -import { cn } from '@/lib/utils'; - -const Select = SelectPrimitive.Root; - -const SelectGroup = SelectPrimitive.Group; - -const SelectValue = SelectPrimitive.Value; - -const SelectTrigger = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, children, ...props }, ref) => ( - span]:line-clamp-1', - className, - )} - {...props} - > - {children} - - - - -)); -SelectTrigger.displayName = SelectPrimitive.Trigger.displayName; - -const SelectScrollUpButton = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - - - -)); -SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName; - -const SelectScrollDownButton = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - - - -)); -SelectScrollDownButton.displayName = - SelectPrimitive.ScrollDownButton.displayName; - -const SelectContent = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, children, position = 'popper', ...props }, ref) => ( - - - - - {children} - - - - -)); -SelectContent.displayName = SelectPrimitive.Content.displayName; - -const SelectLabel = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)); -SelectLabel.displayName = SelectPrimitive.Label.displayName; - -const SelectItem = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, children, ...props }, ref) => ( - - - - - - - - {children} - -)); -SelectItem.displayName = SelectPrimitive.Item.displayName; - -const SelectSeparator = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)); -SelectSeparator.displayName = SelectPrimitive.Separator.displayName; - -export { - Select, - SelectGroup, - SelectValue, - SelectTrigger, - SelectContent, - SelectLabel, - SelectItem, - SelectSeparator, - SelectScrollUpButton, - SelectScrollDownButton, -}; diff --git a/dashboard/src/components/ui/switch.tsx b/dashboard/src/components/ui/switch.tsx deleted file mode 100644 index 4c01734..0000000 --- a/dashboard/src/components/ui/switch.tsx +++ /dev/null @@ -1,29 +0,0 @@ -'use client'; - -import * as React from 'react'; -import * as SwitchPrimitives from '@radix-ui/react-switch'; - -import { cn } from '@/lib/utils'; - -const Switch = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - - - -)); -Switch.displayName = SwitchPrimitives.Root.displayName; - -export { Switch }; diff --git a/dashboard/src/lib/action/client.ts b/dashboard/src/lib/action/client.ts deleted file mode 100644 index fb5156b..0000000 --- a/dashboard/src/lib/action/client.ts +++ /dev/null @@ -1,23 +0,0 @@ -'use server'; - -import { clientFormSchema } from '@/lib/forms/client-form'; -import { z } from 'zod'; -import { getOAuth2Api } from '@/ory/sdk/server'; -import { checkPermission, requireSession } from '@/lib/action/authentication'; -import { permission, relation } from '@/lib/permission'; - -export async function createClient( - formData: z.infer, -) { - - const session = await requireSession(); - const allowed = await checkPermission(permission.client.it, relation.create, session.identity!.id); - if (!allowed) { - throw Error('Unauthorised'); - } - - console.log(session.identity?.traits.email, 'posted form', formData); - - const oauthApi = await getOAuth2Api(); - return await oauthApi.createOAuth2Client({ oAuth2Client: formData }); -} diff --git a/dashboard/src/lib/forms/client-form.ts b/dashboard/src/lib/forms/client-form.ts deleted file mode 100644 index ea3814e..0000000 --- a/dashboard/src/lib/forms/client-form.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { z } from 'zod'; - -export const clientFormSchema = z.object({ - access_token_strategy: z.string().default('opaque').readonly(), - client_name: z.string().min(1, 'Client name is required'), - scope: z.string(), - redirect_uris: z.array(z.string().url({ message: 'Invalid URL' })).min(1, { message: 'At least one redirect URI is required' }), - skip: z.boolean(), - logo_uri: z.string().url(), - tos_uri: z.string().url(), - policy_uri: z.string().url(), - owner: z.string().min(1, 'Owner is required'), - grant_types: z.array(z.string()), - response_types: z.array(z.string()), - token_endpoint_auth_method: z.string(), - backchannel_logout_session_required: z.boolean().default(false), - backchannel_logout_uri: z.string().url(), - frontchannel_logout_session_required: z.boolean().default(false), - frontchannel_logout_uri: z.string().url(), - skip_logout_consent: z.boolean().default(false), - post_logout_redirect_uris: z.array(z.string().url({ message: 'Invalid URL' })).min(1, { message: 'At least one redirect URI is required' }), -}); diff --git a/dashboard/src/lib/permission.ts b/dashboard/src/lib/permission.ts index 38619ac..9fc8ba0 100644 --- a/dashboard/src/lib/permission.ts +++ b/dashboard/src/lib/permission.ts @@ -13,9 +13,6 @@ export const permission = { state: 'admin.user.state', trait: 'admin.user.trait', }, - client: { - it: 'admin.client', - }, }; export const relation = {