First commit
This commit is contained in:
13
src/app.d.ts
vendored
Normal file
13
src/app.d.ts
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
// See https://svelte.dev/docs/kit/types#app.d.ts
|
||||
// for information about these interfaces
|
||||
declare global {
|
||||
namespace App {
|
||||
// interface Error {}
|
||||
// interface Locals {}
|
||||
// interface PageData {}
|
||||
// interface PageState {}
|
||||
// interface Platform {}
|
||||
}
|
||||
}
|
||||
|
||||
export {};
|
||||
12
src/app.html
Normal file
12
src/app.html
Normal file
@@ -0,0 +1,12 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="icon" href="/favicon.png" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
%sveltekit.head%
|
||||
</head>
|
||||
<body data-sveltekit-preload-data="hover">
|
||||
<div style="display: contents; width: 100%">%sveltekit.body%</div>
|
||||
</body>
|
||||
</html>
|
||||
14
src/auth.ts
Normal file
14
src/auth.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import client from "$lib/db"
|
||||
import { MongoDBAdapter } from "@auth/mongodb-adapter"
|
||||
import { SvelteKitAuth } from "@auth/sveltekit"
|
||||
import Keycloak from "@auth/sveltekit/providers/keycloak"
|
||||
|
||||
export const { handle, signIn, signOut } = SvelteKitAuth({
|
||||
providers: [Keycloak],
|
||||
trustHost: true,
|
||||
adapter: MongoDBAdapter(client),
|
||||
session: {
|
||||
maxAge: 14400, // Limit session length to four hours
|
||||
updateAge: 1800, // Update token every 30 minutes
|
||||
},
|
||||
})
|
||||
1
src/hooks.server.ts
Normal file
1
src/hooks.server.ts
Normal file
@@ -0,0 +1 @@
|
||||
export { handle } from "./auth"
|
||||
68
src/lib/HeaderBar.svelte
Normal file
68
src/lib/HeaderBar.svelte
Normal file
@@ -0,0 +1,68 @@
|
||||
<script lang="ts">
|
||||
import { page } from "$app/stores";
|
||||
</script>
|
||||
|
||||
<div id="header-bar">
|
||||
<div id="logo-box">
|
||||
<a href="/">
|
||||
<img class="logo-img" src="/logo/logo-colour.svg" alt="FJLA Logo" width="50" height="50">
|
||||
<!--<img class="logo-img" id="logo-black" src="/logo/logo-black.svg" alt="FJLA Logo" width="50" height="50">
|
||||
--> </a>
|
||||
</div>
|
||||
{#if $page.data.session}
|
||||
<a class="account-link" href="/logout">Sign out</a>
|
||||
{/if}
|
||||
</div>
|
||||
<div id="spacer"></div>
|
||||
|
||||
<style>
|
||||
#header-bar {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
background-color: darkslategrey;
|
||||
height: 60px;
|
||||
}
|
||||
|
||||
#logo-box {
|
||||
padding: 5px;
|
||||
height: 50px;
|
||||
}
|
||||
|
||||
.logo-img {
|
||||
position: absolute;
|
||||
left: 5px;
|
||||
}
|
||||
|
||||
.account-link {
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
top: 0px;
|
||||
height: 60px;
|
||||
width: 140px;
|
||||
color: white;
|
||||
background-color: darkslategrey;
|
||||
font-family: 'Franklin Gothic Medium', 'Arial Narrow', Arial, sans-serif;
|
||||
font-weight: 900;
|
||||
font-size: larger;
|
||||
text-decoration: none;
|
||||
text-align: center;
|
||||
border-radius: 0px;
|
||||
|
||||
/* Flexbox styles for centering */
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
|
||||
.account-link:hover {
|
||||
background-color: rgb(54, 90, 90);
|
||||
}
|
||||
|
||||
#spacer {
|
||||
height: 90px;
|
||||
}
|
||||
|
||||
</style>
|
||||
27
src/lib/app-cards/AppCardArray.svelte
Normal file
27
src/lib/app-cards/AppCardArray.svelte
Normal file
@@ -0,0 +1,27 @@
|
||||
<script lang="ts">
|
||||
import MasterAppCard from "./MasterAppCard.svelte";
|
||||
</script>
|
||||
|
||||
<div id="card-container">
|
||||
<MasterAppCard appName={"My Account"} appDesc={"Manage your password and passkeys"} iconName={"myaccount"} sso={true} appUrl={"https://sso.fjla.uk/realms/FJLA.net/account"} />
|
||||
<MasterAppCard appName={"Nextcloud"} appDesc={"Files, Email, Calendar, Chat"} iconName={"nextcloud"} sso={false} appUrl={"https://cloud.fjla.uk"} bgColor={"#0082c9"} />
|
||||
<MasterAppCard appName={"Portainer"} appDesc={"Manage containerised workloads in Docker"} iconName={"portainer"} sso={true} appUrl={"https://swarm_nodes.fjla.net:9443"} nointernet={true} bgColor={"#3BBCED"} />
|
||||
<MasterAppCard appName={"SpeedyF"} appDesc={"Online Compressor for PDF Files"} iconName={"speedyf"} sso={false} appUrl={"https://speedyf.fjla.uk"} bgColor={"#00001a"} />
|
||||
<MasterAppCard appName={"Jellyfin"} appDesc={"Stream films and TV, watch Live TV"} iconName={"jellyfin"} sso={false} appUrl={"http://jf.fjla.net:8096"} nointernet={true} bgColor={"#AA5CC3"} />
|
||||
<MasterAppCard appName={"Proxmox"} appDesc={"Manage virtual machines"} iconName={"proxmoxve"} sso={true} appUrl={"https://pve0124.fjla.net:8006"} nointernet={true} bgColor={"#e57000"} />
|
||||
<MasterAppCard appName={"Home Assistant"} appDesc={"Smart Home Management"} iconName={"homeassistant"} sso={false} appUrl={"https://ha.fjla.uk"} bgColor={"#18BCF2"} />
|
||||
<MasterAppCard appName={"Gitea"} appDesc={"Code & Package Repo"} iconName={"gitea"} sso={true} appUrl={"https://git.fjla.uk"} bgColor={"#609926"} />
|
||||
</div>
|
||||
|
||||
<style>
|
||||
#card-container {
|
||||
width: 90%;
|
||||
margin: 0 auto;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
gap: 1px;
|
||||
padding: 0px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
</style>
|
||||
0
src/lib/app-cards/CardSettings.ts
Normal file
0
src/lib/app-cards/CardSettings.ts
Normal file
79
src/lib/app-cards/MasterAppCard.svelte
Normal file
79
src/lib/app-cards/MasterAppCard.svelte
Normal file
@@ -0,0 +1,79 @@
|
||||
<script lang="ts">
|
||||
export let appName: string;
|
||||
export let appDesc: string;
|
||||
export let iconName: string;
|
||||
export let sso: boolean;
|
||||
export let nointernet: boolean = false;
|
||||
export let appUrl: string = "#";
|
||||
export let bgColor: string = "rgb(134, 134, 134)"
|
||||
</script>
|
||||
|
||||
<div id="app-card" style="background-color:{bgColor}">
|
||||
<a class="app-link" href={appUrl}>
|
||||
<img src="/icons/{iconName}.svg" alt="{iconName}">
|
||||
<div id="card-text">
|
||||
<header id="app-name">{appName}</header>
|
||||
<p id="app-desc">{appDesc}</p>
|
||||
</div>
|
||||
<div id="sign-on-type">
|
||||
{#if sso}
|
||||
<img src="/logo/logo-black.svg" alt="Single Sign-on" width=25 height=25>
|
||||
{:else}
|
||||
<img src="/icons/not-sso.svg" alt="Single Sign-on not supported" width=25 height=25>
|
||||
{/if}
|
||||
{#if nointernet}
|
||||
<img src="/icons/nointernet.svg" alt="Not available when not connected to FJLA WiFi" width=25 height=25>
|
||||
{/if}
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
|
||||
<style>
|
||||
#app-card {
|
||||
width: calc(25% - 2px);
|
||||
box-sizing: border-box;
|
||||
text-align: center;
|
||||
margin: auto;
|
||||
margin-top: 0px;
|
||||
margin-bottom: 0px;
|
||||
text-decoration: none;
|
||||
color: white;
|
||||
font-family: 'Franklin Gothic Medium', 'Arial Narrow', Arial, sans-serif;
|
||||
padding: 10px;
|
||||
border-radius: 3px;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
/* Responsive styles for smaller screens */
|
||||
@media (max-width: 875px) {
|
||||
#app-card {
|
||||
width: calc(50% - 2px); /* 2 cards per row on smaller screens */
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 676px) {
|
||||
#app-card {
|
||||
width: calc(100% - 2px); /* 1 card per row on very small screens */
|
||||
}
|
||||
}
|
||||
|
||||
#app-card:hover {
|
||||
opacity: 75%;
|
||||
}
|
||||
|
||||
#app-name {
|
||||
font-weight: 600;
|
||||
font-size: larger;
|
||||
}
|
||||
|
||||
#app-desc {
|
||||
margin-top: 10px;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.app-link{
|
||||
text-decoration: none;
|
||||
color: white;
|
||||
}
|
||||
</style>
|
||||
11
src/lib/buttons/Login.svelte
Normal file
11
src/lib/buttons/Login.svelte
Normal file
@@ -0,0 +1,11 @@
|
||||
<script lang="ts">
|
||||
import { SignIn } from "@auth/sveltekit/components";
|
||||
|
||||
</script>
|
||||
|
||||
<SignIn provider="keycloak" redirectTo="/">
|
||||
<div slot="submitButton" class="buttonPrimary">Login</div>
|
||||
</SignIn>
|
||||
|
||||
<style>
|
||||
</style>
|
||||
35
src/lib/db.ts
Normal file
35
src/lib/db.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
import { MongoClient, ServerApiVersion } from "mongodb";
|
||||
|
||||
if (!process.env.MONGODB_URI) {
|
||||
console.log(process.env.MONGODB_URI)
|
||||
console.log("MONGODB_URI Not valid, auth will not work");
|
||||
}
|
||||
|
||||
const uri = process.env.MONGODB_URI || "mongodb://localhost:27017";
|
||||
const options = {
|
||||
serverApi: {
|
||||
version: ServerApiVersion.v1,
|
||||
strict: true,
|
||||
deprecationErrors: true,
|
||||
},
|
||||
};
|
||||
|
||||
let client: MongoClient
|
||||
|
||||
if (process.env.NODE_ENV !== "production") {
|
||||
const globalWithMongo = global as typeof globalThis & {
|
||||
_mongoClient?: MongoClient
|
||||
}
|
||||
|
||||
if (!globalWithMongo._mongoClient) {
|
||||
globalWithMongo._mongoClient = new MongoClient(uri, options)
|
||||
}
|
||||
client = globalWithMongo._mongoClient
|
||||
} else {
|
||||
// In production mode, it's best to not use a global variable.
|
||||
client = new MongoClient(uri, options)
|
||||
}
|
||||
|
||||
// Export a module-scoped MongoClient. By doing this in a
|
||||
// separate module, the client can be shared across functions.
|
||||
export default client
|
||||
1
src/lib/index.ts
Normal file
1
src/lib/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
// place files you want to import through the `$lib` alias in this folder.
|
||||
48
src/lib/notLoggedIn.svelte
Normal file
48
src/lib/notLoggedIn.svelte
Normal file
@@ -0,0 +1,48 @@
|
||||
<script lang="ts">
|
||||
import Login from "./buttons/Login.svelte";
|
||||
</script>
|
||||
|
||||
<div id="content-container">
|
||||
<img id="large-logo" src="/logo/logo-colour.svg" width=125 height=125 alt="Logo">
|
||||
|
||||
<div id="bounding-box">
|
||||
<header>You are not signed in</header>
|
||||
<Login />
|
||||
|
||||
<p>When you login for the first time, you will have to verify your email address and register a passkey to enable your account, <a href="passkey">click here</a> for help.</p>
|
||||
<p><a href="https://sso.fjla.uk/realms/FJLA.net/login-actions/reset-credentials" target="_blank">Forgot your password?</a></p>
|
||||
</div>
|
||||
</div>
|
||||
<style>
|
||||
#content-container {
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
margin: 10 auto;
|
||||
padding: 25px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
#large-logo {
|
||||
margin: 0 auto;
|
||||
}
|
||||
#bounding-box {
|
||||
margin: auto;
|
||||
text-align: center;
|
||||
background-color: lightgrey;
|
||||
width: 75%;
|
||||
min-width: 200px;
|
||||
max-width: 800px;
|
||||
border-radius: 25px;
|
||||
margin-top: 25px;
|
||||
}
|
||||
|
||||
header {
|
||||
font-family: 'Franklin Gothic Medium', 'Arial Narrow', Arial, sans-serif;
|
||||
font-size: large;
|
||||
padding: 15px;
|
||||
}
|
||||
|
||||
p {
|
||||
font-family: 'Franklin Gothic Medium', 'Arial Narrow', Arial, sans-serif;
|
||||
padding: 15px;
|
||||
}
|
||||
</style>
|
||||
9
src/routes/+layout.server.ts
Normal file
9
src/routes/+layout.server.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import type { LayoutServerLoad } from "./$types"
|
||||
|
||||
export const load: LayoutServerLoad = async (event) => {
|
||||
const session = await event.locals.auth()
|
||||
|
||||
return {
|
||||
session,
|
||||
}
|
||||
}
|
||||
4
src/routes/+layout.svelte
Normal file
4
src/routes/+layout.svelte
Normal file
@@ -0,0 +1,4 @@
|
||||
<script lang="ts">
|
||||
</script>
|
||||
|
||||
<slot />
|
||||
8
src/routes/+page.server.ts
Normal file
8
src/routes/+page.server.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import { redirect } from '@sveltejs/kit';
|
||||
import type { PageServerLoad } from './$types';
|
||||
|
||||
export const load: PageServerLoad = async (event) => {
|
||||
const session = await event.locals.auth();
|
||||
if (!session?.user) throw redirect(303, '/login');
|
||||
return {};
|
||||
};
|
||||
37
src/routes/+page.svelte
Normal file
37
src/routes/+page.svelte
Normal file
@@ -0,0 +1,37 @@
|
||||
<script lang="ts">
|
||||
import { page } from "$app/state";
|
||||
import NotLoggedIn from "$lib/notLoggedIn.svelte";
|
||||
import AppCardArray from "$lib/app-cards/AppCardArray.svelte";
|
||||
import HeaderBar from "$lib/HeaderBar.svelte";
|
||||
</script>
|
||||
{#if page.data.session}
|
||||
<HeaderBar />
|
||||
<h1>{page?.data?.session?.user?.name}'s Apps</h1>
|
||||
<div id="icon-key">
|
||||
<img src="/logo/logo-black.svg" alt="FJLA Logo" width=20 height=20> Single Sign On
|
||||
<br>
|
||||
<img src="/icons/not-sso.svg" alt="Separate Password Icon" width=20 height=20 style="background-color:black;border-radius:5px;"> Uses a separate Login
|
||||
<br>
|
||||
<img src="/icons/nointernet.svg" alt="Only on FJLA WiFi" width=20 height=20 style="background-color:black;border-radius:5px;"> Only available on FJLA WiFi
|
||||
</div>
|
||||
<AppCardArray />
|
||||
{:else}
|
||||
<NotLoggedIn />
|
||||
{/if}
|
||||
|
||||
<style>
|
||||
h1 {
|
||||
font-family: 'Franklin Gothic Medium', 'Arial Narrow', Arial, sans-serif;
|
||||
text-align: center;
|
||||
margin: 5px;
|
||||
margin-top: -10px;
|
||||
}
|
||||
|
||||
#icon-key {
|
||||
margin: auto;
|
||||
text-align: center;
|
||||
font-size: 16px;
|
||||
font-family: 'Franklin Gothic Medium', 'Arial Narrow', Arial, sans-serif;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
</style>
|
||||
45
src/routes/backchannel-logout/+server.ts
Normal file
45
src/routes/backchannel-logout/+server.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
const handler = async ({ request }: { request: Request }) => {
|
||||
// Log the HTTP method
|
||||
console.log('HTTP Method:', request.method);
|
||||
|
||||
// Log the full URL
|
||||
console.log('URL:', request.url);
|
||||
|
||||
// Log request headers
|
||||
console.log('Headers:', Object.fromEntries(request.headers.entries()));
|
||||
|
||||
// Log the body, depending on its content type
|
||||
const contentType = request.headers.get('content-type') || '';
|
||||
|
||||
if (contentType.includes('application/json')) {
|
||||
const jsonBody = await request.json();
|
||||
console.log('JSON Body:', JSON.stringify(jsonBody, null, 2));
|
||||
} else if (contentType.includes('application/x-www-form-urlencoded')) {
|
||||
const formData = await request.formData();
|
||||
const formObject: Record<string, string> = {};
|
||||
formData.forEach((value, key) => {
|
||||
formObject[key] = value.toString();
|
||||
});
|
||||
console.log('Form Data:', formObject);
|
||||
} else if (contentType.includes('multipart/form-data')) {
|
||||
const formData = await request.formData();
|
||||
const formObject: Record<string, string> = {};
|
||||
formData.forEach((value, key) => {
|
||||
formObject[key] = value.toString();
|
||||
});
|
||||
console.log('Multipart Form Data:', formObject);
|
||||
} else {
|
||||
const textBody = await request.text();
|
||||
console.log('Text Body:', textBody);
|
||||
}
|
||||
|
||||
return new Response('Request logged!', { status: 200 });
|
||||
};
|
||||
|
||||
// Bind the handler to all HTTP methods
|
||||
export const GET = handler;
|
||||
export const POST = handler;
|
||||
export const PUT = handler;
|
||||
export const DELETE = handler;
|
||||
export const PATCH = handler;
|
||||
export const OPTIONS = handler;
|
||||
21
src/routes/change/+page.svelte
Normal file
21
src/routes/change/+page.svelte
Normal file
@@ -0,0 +1,21 @@
|
||||
<script lang="ts">
|
||||
import { onMount } from "svelte";
|
||||
import { signOut } from "@auth/sveltekit/client";
|
||||
|
||||
const changePwLink: string = "https://sso.fjla.uk/realms/FJLA.net/account/account-security/signing-in"
|
||||
|
||||
onMount(async() => {
|
||||
await signOut();
|
||||
window.location.href = changePwLink;
|
||||
})
|
||||
</script>
|
||||
|
||||
<p>Redirecting, please wait...</p>
|
||||
<p>If the page does not reload <a href={changePwLink}>click here</a>.</p>
|
||||
|
||||
<style>
|
||||
p {
|
||||
text-align: center;
|
||||
margin: auto;
|
||||
}
|
||||
</style>
|
||||
6
src/routes/debug/+page.svelte
Normal file
6
src/routes/debug/+page.svelte
Normal file
@@ -0,0 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { page } from "$app/state";
|
||||
import NotLoggedIn from "$lib/notLoggedIn.svelte";
|
||||
</script>
|
||||
|
||||
<NotLoggedIn />
|
||||
21
src/routes/forgot/+page.svelte
Normal file
21
src/routes/forgot/+page.svelte
Normal file
@@ -0,0 +1,21 @@
|
||||
<script lang="ts">
|
||||
import { onMount } from "svelte";
|
||||
import { signOut } from "@auth/sveltekit/client";
|
||||
|
||||
const changePwLink: string = "https://sso.fjla.uk/realms/FJLA.net/login-actions/reset-credentials"
|
||||
|
||||
onMount(async() => {
|
||||
await signOut();
|
||||
window.location.href = changePwLink;
|
||||
})
|
||||
</script>
|
||||
|
||||
<p>Redirecting, please wait...</p>
|
||||
<p>If the page does not reload <a href={changePwLink}>click here</a>.</p>
|
||||
|
||||
<style>
|
||||
p {
|
||||
text-align: center;
|
||||
margin: auto;
|
||||
}
|
||||
</style>
|
||||
8
src/routes/login/+page.server.ts
Normal file
8
src/routes/login/+page.server.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import { redirect } from '@sveltejs/kit';
|
||||
import type { PageServerLoad } from './$types';
|
||||
|
||||
export const load: PageServerLoad = async (event) => {
|
||||
const session = await event.locals.auth();
|
||||
if (session?.user) throw redirect(303, '/');
|
||||
return {};
|
||||
};
|
||||
5
src/routes/login/+page.svelte
Normal file
5
src/routes/login/+page.svelte
Normal file
@@ -0,0 +1,5 @@
|
||||
<script lang="ts">
|
||||
import NotLoggedIn from "$lib/notLoggedIn.svelte";
|
||||
</script>
|
||||
|
||||
<NotLoggedIn />
|
||||
26
src/routes/logout/+page.svelte
Normal file
26
src/routes/logout/+page.svelte
Normal file
@@ -0,0 +1,26 @@
|
||||
<script lang="ts">
|
||||
import { onMount } from "svelte";
|
||||
import { signOut } from "@auth/sveltekit/client";
|
||||
|
||||
const keycloakUrl = "https://sso.fjla.uk";
|
||||
const keycloakRealm = "FJLA.net";
|
||||
const postLogoutRedirect = "https://fjla.uk/";
|
||||
const clientId = "fjla-home"
|
||||
|
||||
const globalLogoutUrl = `${keycloakUrl}/realms/${keycloakRealm}/protocol/openid-connect/logout?post_logout_redirect_uri=${encodeURIComponent(postLogoutRedirect)}&client_id=${clientId}`;
|
||||
|
||||
onMount(async() => {
|
||||
await signOut();
|
||||
window.location.href = globalLogoutUrl;
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
<p>Signing out...</p>
|
||||
|
||||
<style>
|
||||
p {
|
||||
text-align: center;
|
||||
margin: auto;
|
||||
}
|
||||
</style>
|
||||
52
src/routes/passkey/+page.svelte
Normal file
52
src/routes/passkey/+page.svelte
Normal file
@@ -0,0 +1,52 @@
|
||||
<script lang="ts">
|
||||
|
||||
import HeaderBar from "$lib/HeaderBar.svelte";
|
||||
|
||||
</script>
|
||||
<HeaderBar />
|
||||
|
||||
<header>Passkey Help</header>
|
||||
|
||||
<p>FJLA requires a passkey registered to your account.</p>
|
||||
|
||||
<p>A passkey increases your password by supplementing it, or replacing it completely.</p>
|
||||
|
||||
<p class="subhead">What is a Passkey?</p>
|
||||
|
||||
<p>A passkey is a digital credential that allows users to authenticate and sign into their accounts without using a traditional password. It relies on biometric data such as a fingerprint, face scan, or PIN to verify the user’s identity, ensuring that the sign-in process is both secure and convenient. Passkeys are designed to be resistant to phishing attacks and other forms of cybercrime, as they cannot be stolen or shared like passwords. They are supported by various platforms and can be used across different devices to simplify account registration and improve the overall user experience.</p>
|
||||
|
||||
<p class="subhead">How do I get a Passkey?</p>
|
||||
|
||||
<p>Most mobile devices and many newer computers can act as a passkey themselves. Alternatively, you can purchase a USB passkey - <a href="https://www.yubico.com/gb/product/security-key-nfc-by-yubico-black/" target="_blank">example from Yubico.</a></p>
|
||||
|
||||
<p class="subhead">What's the point?</p>
|
||||
|
||||
<p>By configuring your accounts with a Passkey, security is quickly and easily improved massively. You can use passkeys on many websites and services - if you configure passwordless login, you don't even need to remember a password.</p>
|
||||
|
||||
<p class="subhead">How do I configure passwordless login?</p>
|
||||
|
||||
<p>Login to your FJLA Account on the homepage, then click on My Account, Click on the menu, then 'Account Security', then 'Signing In'. At the bottom of the page, add your passkey in the Passwordless section.</p>
|
||||
<p>If you don't configure passwordless, you will need your password and your passkey to login. Some passkeys do not support passwordless login.</p>
|
||||
|
||||
<style>
|
||||
header {
|
||||
text-align: center;
|
||||
font-size: larger;
|
||||
font-family: 'Franklin Gothic Medium', 'Arial Narrow', Arial, sans-serif;
|
||||
font-weight: 600;
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
|
||||
p {
|
||||
text-align: center;
|
||||
font-family: 'Franklin Gothic Medium', 'Arial Narrow', Arial, sans-serif;
|
||||
margin: auto;
|
||||
width: 80%;
|
||||
max-width: 600px;
|
||||
}
|
||||
|
||||
.subhead {
|
||||
margin-top: 40px;
|
||||
font-weight: 600;
|
||||
}
|
||||
</style>
|
||||
3
src/routes/signin/+page.server.ts
Normal file
3
src/routes/signin/+page.server.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
import { signIn } from "../../auth";
|
||||
import type { Actions } from "./$types";
|
||||
export const actions: Actions = { default: signIn }
|
||||
Reference in New Issue
Block a user