Skip to content

Commit

Permalink
add device views
Browse files Browse the repository at this point in the history
  • Loading branch information
hafezdivandari committed Sep 20, 2024
1 parent d6e9f37 commit 76d028e
Show file tree
Hide file tree
Showing 5 changed files with 235 additions and 0 deletions.
2 changes: 2 additions & 0 deletions src/JetstreamServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,8 @@ protected function bootInertia()

if (class_exists(Passport::class)) {
Passport::authorizationView(fn ($params) => Inertia::render('Auth/OAuth/Authorize', $params));
// Passport::deviceAuthorizationView(fn ($params) => Inertia::render('Auth/OAuth/Device/Authorize', $params));
// Passport::deviceUserCodeView(fn ($params) => Inertia::render('Auth/OAuth/Device/UserCode', $params));
}
}
}
71 changes: 71 additions & 0 deletions stubs/inertia/resources/js/Pages/Auth/OAuth/Device/Authorize.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
<script setup>
import { Head, useForm } from '@inertiajs/vue3';
import AuthenticationCard from '@/Components/AuthenticationCard.vue';
import AuthenticationCardLogo from '@/Components/AuthenticationCardLogo.vue';
import PrimaryButton from '@/Components/PrimaryButton.vue';
import SecondaryButton from '@/Components/SecondaryButton.vue';
const props = defineProps({
user: Object,
client: Object,
scopes: Array,
authToken: String,
});
const form = useForm({
state: route().params.state,
client_id: props.client.id,
auth_token: props.authToken,
});
const approve = () => {
form.post(route('passport.device.authorizations.approve'));
};
const deny = () => {
form.transform(data => ({
...data,
_method: 'delete',
})).post(route('passport.device.authorizations.deny'));
};
</script>

<template>
<Head title="Authorization Request"/>

<AuthenticationCard>
<template #logo>
<AuthenticationCardLogo/>
</template>

<div class="mb-4 text-gray-600 text-center">
<p><strong>{{ user.name }}</strong></p>
<p class="text-sm">{{ user.email }}</p>
</div>

<div class="mb-4 text-sm text-gray-600">
<strong>{{ client.name }}</strong> is requesting permission to access your account.
</div>

<div v-if="scopes.length" class="mb-4 text-sm text-gray-600">
<p class="pb-1">This application will be able to:</p>

<ul class="list-inside list-disc">
<li v-for="scope in scopes">{{ scope.description }}</li>
</ul>
</div>

<div class="flex flex-row-reverse gap-3 mt-4 flex-wrap items-center">
<form @submit.prevent="approve">
<PrimaryButton :class="{ 'opacity-25': form.processing }" :disabled="form.processing">
Authorize
</PrimaryButton>
</form>

<form @submit.prevent="deny">
<SecondaryButton type="submit" :class="{ 'opacity-25': form.processing }" :disabled="form.processing">
Decline
</SecondaryButton>
</form>
</div>
</AuthenticationCard>
</template>
71 changes: 71 additions & 0 deletions stubs/inertia/resources/js/Pages/Auth/OAuth/Device/UserCode.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
<script setup>
import { computed } from 'vue';
import { Head, useForm } from '@inertiajs/vue3';
import AuthenticationCard from '@/Components/AuthenticationCard.vue';
import AuthenticationCardLogo from '@/Components/AuthenticationCardLogo.vue';
import InputError from '@/Components/InputError.vue';
import InputLabel from '@/Components/InputLabel.vue';
import PrimaryButton from '@/Components/PrimaryButton.vue';
import TextInput from '@/Components/TextInput.vue';
defineProps({
status: String,
});
const form = useForm({
user_code: '',
});
const submit = () => {
form.get(route('passport.device.authorizations.authorize'));
};
const authorizationApproved = computed(() => props.status === 'authorization-approved');
const authorizationDenied = computed(() => props.status === 'authorization-denied');
</script>

<template>
<Head title="Connect a Device" />

<AuthenticationCard>
<template #logo>
<AuthenticationCardLogo />
</template>

<div v-if="authorizationApproved" class="mb-4 font-medium text-sm text-green-600 dark:text-green-400">
Success! Continue on your device.
</div>
<div v-else-if="authorizationDenied" class="mb-4 font-medium text-sm text-red-600 dark:text-red-400">
Denied! Device authorization canceled.
</div>

<div class="mb-4 text-sm text-gray-600 dark:text-gray-400">
Enter the code displayed on your device.
</div>

<form @submit.prevent="submit">
<div>
<InputLabel for="user_code" value="Code" />
<TextInput
id="user_code"
v-model="form.user_code"
type="text"
class="mt-1 block w-full"
required
autofocus
autocomplete="off"
autocapitalize="characters"
autocorrect="off"
spellcheck="false"
/>
<InputError class="mt-2" :message="form.errors.user_code" />
</div>

<div class="flex items-center justify-end mt-4">
<PrimaryButton :class="{ 'opacity-25': form.processing }" :disabled="form.processing">
Continue
</PrimaryButton>
</div>
</form>
</AuthenticationCard>
</template>
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<x-guest-layout>
<x-authentication-card>
<x-slot name="logo">
<x-authentication-card-logo />
</x-slot>

<div class="mb-4 text-gray-600 text-center">
<p><strong>{{ $user->name }}</strong></p>
<p class="text-sm">{{ $user->email }}</p>
</div>

<div class="mb-4 text-sm text-gray-600">
{{ __(':client is requesting permission to access your account.', ['client' => $client->name]) }}
</div>

@if (count($scopes) > 0)
<div class="mb-4 text-sm text-gray-600">
<p class="pb-1">{{ __('This application will be able to:') }}</p>

<ul class="list-inside list-disc">
@foreach ($scopes as $scope)
<li>{{ $scope->description }}</li>
@endforeach
</ul>
</div>
@endif

<div class="flex flex-row-reverse gap-3 mt-4 flex-wrap items-center">
<form method="POST" action="{{ route('passport.device.authorizations.approve') }}">
@csrf

<input type="hidden" name="state" value="{{ $request->state }}">
<input type="hidden" name="client_id" value="{{ $client->getKey() }}">
<input type="hidden" name="auth_token" value="{{ $authToken }}">

<x-button>
{{ __('Authorize') }}
</x-button>
</form>

<form method="POST" action="{{ route('passport.device.authorizations.deny') }}">
@csrf
@method('DELETE')

<input type="hidden" name="state" value="{{ $request->state }}">
<input type="hidden" name="client_id" value="{{ $client->getKey() }}">
<input type="hidden" name="auth_token" value="{{ $authToken }}">

<x-secondary-button type="submit">
{{ __('Decline') }}
</x-secondary-button>
</form>
</div>
</x-authentication-card>
</x-guest-layout>
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<x-guest-layout>
<x-authentication-card>
<x-slot name="logo">
<x-authentication-card-logo />
</x-slot>

@if (session('status') === 'authorization-approved')
<div class="mb-4 font-medium text-sm text-green-600 dark:text-green-400">
{{ __('Success! Continue on your device.') }}
</div>
@elseif(session('status') === 'authorization-denied')
<div class="mb-4 font-medium text-sm text-red-600 dark:text-red-400">
{{ __('Denied! Device authorization canceled.') }}
</div>
@endif

<div class="mb-4 text-sm text-gray-600 dark:text-gray-400">
{{ __('Enter the code displayed on your device.') }}
</div>

<x-validation-errors class="mb-4" />

<form method="GET" action="{{ route('passport.device.authorizations.authorize') }}">
<div class="block">
<x-label for="user_code" value="{{ __('Code') }}" />
<x-input id="user_code" class="block mt-1 w-full" type="text" name="user_code" :value="old('user_code')" required autofocus autocomplete="off" autocapitalize="characters" autocorrect="off" spellcheck="false" />
</div>

<div class="flex items-center justify-end mt-4">
<x-button>
{{ __('Continue') }}
</x-button>
</div>
</form>
</x-authentication-card>
</x-guest-layout>

0 comments on commit 76d028e

Please sign in to comment.