1
0
mirror of https://github.com/pocket-id/pocket-id.git synced 2026-02-09 03:49:19 +00:00

feat: device authorization endpoint (#270)

Co-authored-by: Elias Schneider <login@eliasschneider.com>
This commit is contained in:
Kyle Mendell
2025-04-25 12:14:51 -05:00
committed by GitHub
parent 630327c979
commit 22f7d64bf0
26 changed files with 778 additions and 80 deletions

View File

@@ -5,7 +5,7 @@
import Logo from '../logo.svelte';
import HeaderAvatar from './header-avatar.svelte';
const authUrls = [/^\/authorize$/, /^\/login(?:\/.*)?$/, /^\/logout$/];
const authUrls = [/^\/authorize$/, /^\/device$/, /^\/login(?:\/.*)?$/, /^\/logout$/];
let isAuthPage = $derived(
!page.error && authUrls.some((pattern) => pattern.test(page.url.pathname))

View File

@@ -0,0 +1,13 @@
<script lang="ts">
export let icon: ConstructorOfATypedSvelteComponent;
export let name: string;
export let description: string;
</script>
<div class="flex items-center">
<div class="mr-5 rounded-lg bg-muted p-2"><svelte:component this={icon} /></div>
<div class="text-start">
<h3 class="font-semibold">{name}</h3>
<p class="text-sm text-muted-foreground">{description}</p>
</div>
</div>

View File

@@ -0,0 +1,27 @@
<script lang="ts">
import { m } from '$lib/paraglide/messages';
import { LucideMail, LucideUser, LucideUsers } from 'lucide-svelte';
import ScopeItem from './scope-item.svelte';
let { scope }: { scope: string } = $props();
</script>
<div class="flex flex-col gap-3" data-testid="scopes">
{#if scope!.includes('email')}
<ScopeItem icon={LucideMail} name={m.email()} description={m.view_your_email_address()} />
{/if}
{#if scope!.includes('profile')}
<ScopeItem
icon={LucideUser}
name={m.profile()}
description={m.view_your_profile_information()}
/>
{/if}
{#if scope!.includes('groups')}
<ScopeItem
icon={LucideUsers}
name={m.groups()}
description={m.view_the_groups_you_are_a_member_of()}
/>
{/if}
</div>

View File

@@ -1,5 +1,6 @@
import type {
AuthorizeResponse,
OidcDeviceCodeInfo,
OidcClient,
OidcClientCreate,
OidcClientMetaData,
@@ -8,6 +9,7 @@ import type {
import type { Paginated, SearchPaginationSortRequest } from '$lib/types/pagination.type';
import APIService from './api-service';
class OidcService extends APIService {
async authorize(
clientId: string,
@@ -92,6 +94,15 @@ class OidcService extends APIService {
const res = await this.api.put(`/oidc/clients/${id}/allowed-user-groups`, { userGroupIds });
return res.data as OidcClientWithAllowedUserGroups;
}
async verifyDeviceCode(userCode: string) {
return await this.api.post(`/oidc/device/verify?code=${userCode}`);
}
async getDeviceCodeInfo(userCode: string): Promise<OidcDeviceCodeInfo> {
const response = await this.api.get(`/oidc/device/info?code=${userCode}`);
return response.data;
}
}
export default OidcService;

View File

@@ -23,6 +23,12 @@ export type OidcClientCreateWithLogo = OidcClientCreate & {
logo: File | null | undefined;
};
export type OidcDeviceCodeInfo = {
scope: string;
authorizationRequired: boolean;
client: OidcClientMetaData;
};
export type AuthorizeResponse = {
code: string;
callbackURL: string;