Skip to content

Commit 0d28ec8

Browse files
authored
Merge pull request #191 from frontendmu/163-github-login
Github SSO
2 parents 3f3e460 + b06ef97 commit 0d28ec8

18 files changed

+456
-164
lines changed

packages/frontendmu-nuxt/auth-utils/useAuth.ts

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ export default function useAuth(client: DirectusClient<any> & AuthenticationClie
114114
credentials: 'include', // this is required in order to send the refresh token cookie
115115
body: JSON.stringify({
116116
refresh_token: getCookieValue('directus_session_token'),
117+
mode: 'cookie',
117118
}),
118119
},
119120
)
@@ -171,10 +172,12 @@ export default function useAuth(client: DirectusClient<any> & AuthenticationClie
171172
'meal',
172173
'occupation',
173174
'github_username',
175+
'external_identifier',
174176
'Events.Events_id.id',
175177
'Events.Events_id.title',
176178
'profile_picture',
177179
'role.name',
180+
'provider',
178181
]
179182

180183
try {
@@ -220,9 +223,21 @@ export default function useAuth(client: DirectusClient<any> & AuthenticationClie
220223
return false
221224
})
222225

223-
function oAuthLogin() {
224-
const currentPage = new URL(window.location.origin)
225-
return `${DIRECTUS_URL()}/auth/login/google?redirect=${currentPage}redirect`
226+
function oAuthLogin(provider: string) {
227+
if (provider === 'google') {
228+
const currentPage = new URL(window.location.origin)
229+
return `${DIRECTUS_URL()}/auth/login/google?redirect=${currentPage}redirect`
230+
}
231+
else if (provider === 'github') {
232+
const currentPage = new URL(window.location.origin)
233+
return `${DIRECTUS_URL()}/auth/login/github?redirect=${currentPage}redirect`
234+
}
235+
else if (provider === 'discord') {
236+
const currentPage = new URL(window.location.origin)
237+
return `${DIRECTUS_URL()}/auth/login/discord?redirect=${currentPage}redirect`
238+
}
239+
240+
console.log('Provider not found')
226241
}
227242

228243
async function updateUserProfile({ profile_updates }: { profile_updates: DirectusAstroUser }) {

packages/frontendmu-nuxt/components/auth/LoggedUser.vue

Lines changed: 48 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -1,103 +1,81 @@
11
<script setup lang="ts">
2-
import { onMounted } from "vue";
3-
import { Menu, MenuButton, MenuItem, MenuItems } from "@headlessui/vue";
4-
import useAuth, { getClient } from "../../auth-utils/useAuth";
5-
import useAuthRedirect from "@/auth-utils/useAuthRedirect";
2+
import { onMounted } from 'vue'
3+
import { Menu, MenuButton, MenuItem, MenuItems } from '@headlessui/vue'
4+
import useAuth, { getClient } from '../../auth-utils/useAuth'
5+
import useAuthRedirect from '@/auth-utils/useAuthRedirect'
66
77
const { user, logout, isLoggedIn, checkIfLoggedIn, avatarUrl } = useAuth(
8-
getClient()
9-
);
8+
getClient(),
9+
)
1010
11-
const { setUrl } = useAuthRedirect();
11+
const { setUrl } = useAuthRedirect()
1212
1313
onMounted(() => {
14-
checkIfLoggedIn();
15-
});
14+
checkIfLoggedIn()
15+
})
1616
</script>
1717

1818
<template>
1919
<div class="dark:text-zinc-200 dark:ring-white/10 pl-4">
20-
<BaseButton
21-
v-if="!isLoggedIn"
22-
href="/login"
23-
color="primary"
24-
class="font-medium hidden md:block"
25-
@click="setUrl()"
26-
>
27-
Log In
28-
</BaseButton>
29-
<BaseButton
30-
v-if="!isLoggedIn"
31-
href="/login"
32-
color="primary"
33-
class="font-medium block md:hidden"
34-
size="sm"
35-
@click="setUrl()"
36-
>
20+
<BaseButton v-if="!isLoggedIn" href="/login" color="primary" class="font-medium hidden md:block" size="sm"
21+
@click="setUrl()">
3722
Log In
3823
</BaseButton>
3924
<div v-else class="flex gap-2 items-center">
4025
<Menu as="div" class="relative inline-block text-left">
4126
<div>
4227
<MenuButton
43-
class="inline-flex items-center w-full justify-center gap-x-1.5 rounded-full text-sm font-semibold text-verse-900 dark:text-verse-100 shadow-sm ring-gray-300 hover:bg-gray-50"
44-
>
45-
<div v-if="avatarUrl">
46-
<img
47-
class="w-10 aspect-square rounded-full"
48-
:src="avatarUrl"
49-
alt="User Avatar"
50-
/>
28+
class="inline-flex relative items-center w-full justify-center gap-x-1.5 rounded-full text-sm font-semibold text-verse-900 dark:text-verse-100 shadow-sm ring-gray-300 hover:bg-gray-50">
29+
<template v-if="user?.provider === 'github'">
30+
<img class="w-10 aspect-square rounded-full" :src="`https://github.com/${user?.external_identifier}.png`">
31+
</template>
32+
<template v-else>
33+
<div v-if="avatarUrl">
34+
<img class="w-10 aspect-square rounded-full" :src="avatarUrl" alt="User Avatar">
35+
</div>
36+
</template>
37+
<!-- Provider Hint -->
38+
<div class="absolute bottom-0 right-0 bg-white rounded-full">
39+
<div v-if="user?.provider === 'default'">
40+
<Icon class="block w-3 h-3 p-0.5 text-black" name="fluent:animal-rabbit-24-regular" />
41+
</div>
42+
<div v-else>
43+
<Icon :name="`carbon:logo-${user?.provider}`" class="block w-3 h-3 p-0.5 text-black" />
44+
</div>
5145
</div>
5246
</MenuButton>
5347
</div>
5448

55-
<transition
56-
enter-active-class="transition ease-out duration-100"
57-
enter-from-class="transform opacity-0 scale-95"
58-
enter-to-class="transform opacity-100 scale-100"
59-
leave-active-class="transition ease-in duration-75"
60-
leave-from-class="transform opacity-100 scale-100"
61-
leave-to-class="transform opacity-0 scale-95"
62-
>
49+
<transition enter-active-class="transition ease-out duration-100"
50+
enter-from-class="transform opacity-0 scale-95" enter-to-class="transform opacity-100 scale-100"
51+
leave-active-class="transition ease-in duration-75" leave-from-class="transform opacity-100 scale-100"
52+
leave-to-class="transform opacity-0 scale-95">
6353
<MenuItems
64-
class="absolute right-0 z-10 mt-2 w-56 origin-top-right divide-y divide-gray-100/10 rounded-md bg-zinc-500/20 dark:bg-verse-500/20 backdrop-blur-2xl shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none"
65-
>
54+
class="absolute right-0 z-10 mt-2 w-56 origin-top-right divide-y divide-gray-100/10 rounded-md bg-zinc-500/20 dark:bg-verse-500/20 backdrop-blur-2xl shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none">
6655
<div class="py-1">
6756
<MenuItem v-slot="{ active }">
68-
<NuxtLink
69-
href="/user/me"
70-
class="block px-4 py-2 text-sm"
71-
:class="[
72-
active
73-
? 'bg-gray-400/10 text-verse-900 dark:text-verse-100'
74-
: 'text-verse-900 dark:text-verse-100',
75-
]"
76-
>
77-
My Profile
78-
</NuxtLink>
57+
<NuxtLink href="/user/me" class="block px-4 py-2 text-sm" :class="[
58+
active
59+
? 'bg-gray-400/10 text-verse-900 dark:text-verse-100'
60+
: 'text-verse-900 dark:text-verse-100',
61+
]">
62+
My Profile
63+
</NuxtLink>
7964
</MenuItem>
8065
<MenuItem v-slot="{ active }">
81-
<NuxtLink
82-
class="block px-4 py-2 text-sm cursor-pointer"
83-
:class="[
84-
active
85-
? 'bg-gray-400/10 text-verse-900 dark:text-verse-100'
86-
: 'text-verse-900 dark:text-verse-100',
87-
]"
88-
@click="logout()"
89-
>
90-
Logout
91-
</NuxtLink>
66+
<NuxtLink class="block px-4 py-2 text-sm cursor-pointer" :class="[
67+
active
68+
? 'bg-gray-400/10 text-verse-900 dark:text-verse-100'
69+
: 'text-verse-900 dark:text-verse-100',
70+
]" @click="logout()">
71+
Logout
72+
</NuxtLink>
9273
</MenuItem>
9374
</div>
9475
<div class="text-verse-900 dark:text-verse-100 p-4 text-sm">
9576
<div class="flex flex-col items-center justify-center gap-2">
9677
<div v-if="avatarUrl">
97-
<img
98-
class="w-16 aspect-square rounded-full"
99-
:src="avatarUrl"
100-
/>
78+
<img class="w-16 aspect-square rounded-full" :src="avatarUrl">
10179
</div>
10280

10381
{{ user?.full_name }}

packages/frontendmu-nuxt/components/auth/LoginForm.vue

Lines changed: 26 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@ const developmentEnvironment = process.env.NODE_ENV === 'development'
2828
</h2>
2929
</div>
3030
<div class="mt-10 sm:mx-auto sm:w-full sm:max-w-[480px] flex justify-center">
31-
<div class="bg-verse-200/10 overflow-hidden dark:bg-verse-500/20 backdrop-blur-sm px-6 py-12 shadow-2xl rounded-lg sm:px-12 w-11/12">
31+
<div
32+
class="bg-verse-200/10 overflow-hidden dark:bg-verse-500/20 backdrop-blur-sm px-6 py-12 shadow-2xl rounded-lg sm:px-12 w-11/12">
3233
<div v-if="isLoggedIn">
3334
<div class="text-center flex flex-col gap-8 text-verse-900 dark:text-verse-100 w-full">
3435
<span>
@@ -52,41 +53,24 @@ const developmentEnvironment = process.env.NODE_ENV === 'development'
5253
<div v-else>
5354
<form v-if="developmentEnvironment" class="space-y-6" @submit.prevent="login()">
5455
<div>
55-
<label
56-
for="email"
57-
class="block text-sm font-medium leading-6 text-verse-900 dark:text-verse-100"
58-
>
56+
<label for="email" class="block text-sm font-medium leading-6 text-verse-900 dark:text-verse-100">
5957
Email address
6058
</label>
6159
<div class="mt-2">
62-
<input
63-
id="email"
64-
v-model="email"
65-
name="email"
66-
type="email"
67-
autocomplete="email"
60+
<input id="email" v-model="email" name="email" type="email" autocomplete="email"
6861
class="block w-full rounded-md border-0 p-1.5 text-verse-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-verse-600 sm:text-sm sm:leading-6"
69-
required
70-
>
62+
required>
7163
</div>
7264
</div>
7365

7466
<div>
75-
<label
76-
for="password"
77-
class="block text-sm font-medium leading-6 text-verse-900 dark:text-verse-100"
78-
>
67+
<label for="password" class="block text-sm font-medium leading-6 text-verse-900 dark:text-verse-100">
7968
Password
8069
</label>
8170
<div class="mt-2">
82-
<input
83-
id="password"
84-
v-model="password"
85-
name="password"
86-
type="password"
87-
autocomplete="current-password" required
88-
class="block w-full rounded-md border-0 p-1.5 text-verse-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-verse-600 sm:text-sm sm:leading-6"
89-
>
71+
<input id="password" v-model="password" name="password" type="password" autocomplete="current-password"
72+
required
73+
class="block w-full rounded-md border-0 p-1.5 text-verse-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-verse-600 sm:text-sm sm:leading-6">
9074
</div>
9175
</div>
9276

@@ -103,10 +87,8 @@ const developmentEnvironment = process.env.NODE_ENV === 'development'
10387
</div> -->
10488

10589
<div>
106-
<button
107-
type="submit"
108-
class="flex w-full justify-center rounded-md bg-verse-600 px-3 py-1.5 text-sm font-semibold leading-6 text-white shadow-sm hover:bg-verse-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-verse-600"
109-
>
90+
<button type="submit"
91+
class="flex w-full justify-center rounded-md bg-verse-600 px-3 py-1.5 text-sm font-semibold leading-6 text-white shadow-sm hover:bg-verse-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-verse-600">
11092
Sign in
11193
</button>
11294
</div>
@@ -124,36 +106,31 @@ const developmentEnvironment = process.env.NODE_ENV === 'development'
124106
</div>
125107

126108
<div class="mt-10 grid sm:grid-cols-2 gap-4">
127-
<a
128-
:href="oAuthLogin()"
129-
class="flex w-full items-center justify-center gap-3 rounded-md bg-[#000000] hover:bg-black/50 transition-all duration-300 px-3 py-1.5 text-white focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[#1D9BF0]"
130-
>
109+
<a :href="oAuthLogin('google')"
110+
class="flex w-full items-center justify-center gap-3 rounded-md bg-[#000000] hover:bg-black/50 transition-all duration-300 px-3 py-1.5 text-white focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[#1D9BF0]">
131111
<Icon name="logos:google-icon" class="h-5 w-5" />
132112
<span class="text-sm font-semibold leading-6">Google</span>
133113
</a>
134114

135-
<a
136-
href="#"
137-
class="opacity-60 cursor-not-allowed flex w-full items-center justify-center gap-3 rounded-md bg-[#24292F] px-3 py-1.5 text-white focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[#24292F]"
115+
<AuthLoginWithGithub />
116+
117+
<!-- <a
118+
:href="oAuthLogin('discord')"
119+
class="flex w-full items-center justify-center gap-3 rounded-md bg-[#000000] hover:bg-black/50 px-3 py-1.5 text-white focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[#24292F]"
138120
disabled
139121
>
140-
<svg class="h-5 w-5" aria-hidden="true" fill="currentColor" viewBox="0 0 20 20">
141-
<path
142-
fill-rule="evenodd"
143-
d="M10 0C4.477 0 0 4.484 0 10.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0110 4.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.203 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.942.359.31.678.921.678 1.856 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0020 10.017C20 4.484 15.522 0 10 0z"
144-
clip-rule="evenodd"
145-
/>
146-
</svg>
147-
<span class="text-sm font-semibold leading-6">GitHub</span>
148-
</a>
122+
<Icon
123+
name="logos:discord-icon"
124+
class="h-5 w-5"
125+
/>
126+
<span class="text-sm font-semibold leading-6">Discord</span>
127+
</a> -->
149128
</div>
150129
</div>
151130
</div>
152131

153-
<div
154-
class="absolute bottom-0 left-0 bg-zinc-500/20 dark:bg-verse-500/20 backdrop-blur-2xl right-0 z-10 h-0"
155-
:style="{ height: countDownPercentage }"
156-
/>
132+
<div class="absolute bottom-0 left-0 bg-zinc-500/20 dark:bg-verse-500/20 backdrop-blur-2xl right-0 z-10 h-0"
133+
:style="{ height: countDownPercentage }" />
157134
</div>
158135
</div>
159136
</template>
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
<script setup lang="ts">
2+
import useAuth, { getClient } from '@/auth-utils/useAuth'
3+
import {
4+
AlertDialog,
5+
AlertDialogAction,
6+
AlertDialogCancel,
7+
AlertDialogContent,
8+
AlertDialogDescription,
9+
AlertDialogFooter,
10+
AlertDialogHeader,
11+
AlertDialogTitle,
12+
AlertDialogTrigger,
13+
} from '@/components/ui/alert-dialog'
14+
import { Button } from '@/components/ui/button'
15+
16+
const { oAuthLogin } = useAuth(getClient())
17+
18+
function triggerRedirectToGithub() {
19+
window.location.href = oAuthLogin('github')!
20+
}
21+
</script>
22+
23+
<template>
24+
<AlertDialog>
25+
<AlertDialogTrigger as-child>
26+
<div class="flex w-full items-center justify-center gap-3 rounded-md bg-[#000000] hover:bg-black/50 px-3 py-1.5 text-white focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[#24292F]"
27+
disabled>
28+
<svg class="h-5 w-5" aria-hidden="true" fill="currentColor" viewBox="0 0 20 20">
29+
<path fill-rule="evenodd"
30+
d="M10 0C4.477 0 0 4.484 0 10.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0110 4.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.203 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.942.359.31.678.921.678 1.856 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0020 10.017C20 4.484 15.522 0 10 0z"
31+
clip-rule="evenodd" />
32+
</svg>
33+
<span class="text-sm font-semibold leading-6">GitHub</span>
34+
</div>
35+
</AlertDialogTrigger>
36+
<AlertDialogContent class="border-white/20">
37+
<AlertDialogHeader>
38+
<AlertDialogTitle class="flex gap-2 items-center">
39+
<Icon name="carbon:logo-github" class="block w-5 h-5 p-0.5 " />
40+
41+
Login with GitHub is experimental !
42+
</AlertDialogTitle>
43+
<AlertDialogDescription>
44+
<ol class="list-decimal list-outside pl-4 space-y-2">
45+
<li>
46+
Make sure your email address is <a target="_blank" class="underline"
47+
href="https://github.com/settings/emails#toggle_visibility_note">publicly visible on
48+
GitHub. </a>
49+
</li>
50+
<li>
51+
If you have logged in with a Google account previously, the same email will not work if it's
52+
associated to your github account.
53+
</li>
54+
</ol>
55+
</AlertDialogDescription>
56+
</AlertDialogHeader>
57+
<AlertDialogFooter>
58+
<AlertDialogCancel>Cancel</AlertDialogCancel>
59+
<AlertDialogAction @click="triggerRedirectToGithub()">
60+
Continue
61+
</AlertDialogAction>
62+
</AlertDialogFooter>
63+
</AlertDialogContent>
64+
</AlertDialog>
65+
</template>

0 commit comments

Comments
 (0)