mirror of
https://github.com/Dan6erbond/sk-auth.git
synced 2025-04-23 01:16:26 +02:00
Merge branch 'main' into feature/discord-provider
This commit is contained in:
commit
9a8ffa9397
@ -1,3 +1,4 @@
|
||||
README.md
|
||||
app/
|
||||
*.cjs
|
||||
dist/
|
||||
|
2
.gitignore
vendored
2
.gitignore
vendored
@ -76,4 +76,4 @@ typings/
|
||||
.fusebox/
|
||||
|
||||
# Build output
|
||||
dist/*
|
||||
dist/
|
||||
|
@ -144,6 +144,10 @@ SvelteKitAuth is inspired by the [NextAuth.js](https://next-auth.js.org/) packag
|
||||
|
||||
As it leverages classes and Typescript, the implementation of such providers is very straightforward, and in the future it will even be possible to register multiple SvelteKitAuth handlers in the same project, should the need arise, by leveraging a class-based client and server setup.
|
||||
|
||||
## Examples
|
||||
|
||||
Looking for help? Check out the [example app](./app/) in the repository source. Make something cool you want to show off? Share it with others [in the discussion section](https://github.com/Dan6erbond/sk-auth/discussions/72).
|
||||
|
||||
## Contributing
|
||||
|
||||
🚧 Work in Progress!
|
||||
|
@ -1,2 +1,6 @@
|
||||
node_modules/
|
||||
README.md
|
||||
*.cjs
|
||||
.svelte-kit/
|
||||
static/
|
||||
build/
|
||||
|
@ -9,7 +9,7 @@
|
||||
"format": "prettier --write --plugin-search-dir=. ."
|
||||
},
|
||||
"devDependencies": {
|
||||
"@sveltejs/kit": "next",
|
||||
"@sveltejs/kit": "^1.0.0-next.259",
|
||||
"@types/prismjs": "^1.16.5",
|
||||
"@typescript-eslint/eslint-plugin": "^4.19.0",
|
||||
"@typescript-eslint/parser": "^4.19.0",
|
||||
|
@ -1,13 +1,15 @@
|
||||
import type { Handle } from "@sveltejs/kit";
|
||||
import { appAuth } from "$lib/appAuth";
|
||||
|
||||
export const handle: Handle = async ({ request, render }) => {
|
||||
export const handle: Handle = async ({ event, resolve }) => {
|
||||
// TODO https://github.com/sveltejs/kit/issues/1046
|
||||
if (request.query.has("_method")) {
|
||||
request.method = request.query.get("_method").toUpperCase();
|
||||
|
||||
|
||||
if (event.request.query.has("_method")) {
|
||||
event.request.method = event.request.query.get("_method").toUpperCase();
|
||||
}
|
||||
|
||||
const response = await render(request);
|
||||
const response = await resolve(event);
|
||||
|
||||
return response;
|
||||
};
|
||||
|
3302
app/yarn.lock
3302
app/yarn.lock
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "sk-auth",
|
||||
"version": "0.4.0",
|
||||
"version": "0.4.1",
|
||||
"description": "Authentication library for use with SvelteKit featuring built-in OAuth providers and zero restriction customization!",
|
||||
"main": "dist/index.js",
|
||||
"module": "dist/index.esm.js",
|
||||
@ -18,6 +18,7 @@
|
||||
"README.md"
|
||||
],
|
||||
"scripts": {
|
||||
"prepare": "npm run build",
|
||||
"build": "rollup --config",
|
||||
"dev": "rollup --config --watch",
|
||||
"test": "echo \"Error: no test specified\" && exit 1",
|
||||
@ -47,7 +48,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@rollup/plugin-typescript": "^8.2.1",
|
||||
"@sveltejs/kit": "^1.0.0-next.211",
|
||||
"@sveltejs/kit": "^1.0.0-next.259",
|
||||
"@types/jsonwebtoken": "^8.5.1",
|
||||
"@typescript-eslint/eslint-plugin": "^4.23.0",
|
||||
"@typescript-eslint/parser": "^4.23.0",
|
||||
|
51
src/auth.ts
51
src/auth.ts
@ -1,7 +1,6 @@
|
||||
import type { GetSession, RequestHandler } from "@sveltejs/kit";
|
||||
import type { EndpointOutput } from "@sveltejs/kit/types/endpoint";
|
||||
import { RequestHeaders } from "@sveltejs/kit/types/helper";
|
||||
import { ServerRequest } from "@sveltejs/kit/types/hooks";
|
||||
import { RequestEvent } from "@sveltejs/kit/types/hooks";
|
||||
import cookie from "cookie";
|
||||
import * as jsonwebtoken from "jsonwebtoken";
|
||||
import type { JWT, Session } from "./interfaces";
|
||||
@ -45,12 +44,12 @@ export class Auth {
|
||||
return "svelte_auth_secret";
|
||||
}
|
||||
|
||||
async getToken(headers: RequestHeaders) {
|
||||
if (!headers.cookie) {
|
||||
async getToken(headers: any) {
|
||||
if (!headers.get("cookie")) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const cookies = cookie.parse(headers.cookie);
|
||||
const cookies = cookie.parse(headers.get("cookie"));
|
||||
|
||||
if (!cookies.svelteauthjwt) {
|
||||
return null;
|
||||
@ -71,7 +70,7 @@ export class Auth {
|
||||
}
|
||||
|
||||
getBaseUrl(host?: string) {
|
||||
const protocol = this.config?.protocol ?? "http";
|
||||
const protocol = this.config?.protocol ?? "https";
|
||||
host = this.config?.host ?? host;
|
||||
return `${protocol}://${host}`;
|
||||
}
|
||||
@ -86,7 +85,7 @@ export class Auth {
|
||||
return new URL(pathname, this.getBaseUrl(host)).href;
|
||||
}
|
||||
|
||||
setToken(headers: RequestHeaders, newToken: JWT | any) {
|
||||
setToken(headers: any, newToken: JWT | any) {
|
||||
const originalToken = this.getToken(headers);
|
||||
|
||||
return {
|
||||
@ -113,12 +112,10 @@ export class Auth {
|
||||
return redirect;
|
||||
}
|
||||
|
||||
async handleProviderCallback(
|
||||
request: ServerRequest,
|
||||
provider: Provider,
|
||||
): Promise<EndpointOutput> {
|
||||
const { headers, url } = request;
|
||||
const [profile, redirectUrl] = await provider.callback(request, this);
|
||||
async handleProviderCallback(event: RequestEvent, provider: Provider): Promise<EndpointOutput> {
|
||||
const { headers } = event.request;
|
||||
const { url } = event;
|
||||
const [profile, redirectUrl] = await provider.callback(event, this);
|
||||
|
||||
let token = (await this.getToken(headers)) ?? { user: {} };
|
||||
if (this.config?.callbacks?.jwt) {
|
||||
@ -139,11 +136,12 @@ export class Auth {
|
||||
};
|
||||
}
|
||||
|
||||
async handleEndpoint(request: ServerRequest): Promise<EndpointOutput> {
|
||||
const { headers, method, url } = request;
|
||||
async handleEndpoint(event: RequestEvent): Promise<EndpointOutput> {
|
||||
const { headers, method } = event.request;
|
||||
const { url } = event;
|
||||
|
||||
if (url.pathname === this.getPath("signout")) {
|
||||
const token = this.setToken(headers, {});
|
||||
const token = this.setToken(event.request.headers, {});
|
||||
const jwt = this.signToken(token);
|
||||
|
||||
if (method === "POST") {
|
||||
@ -177,9 +175,9 @@ export class Auth {
|
||||
);
|
||||
if (provider) {
|
||||
if (match.groups.method === "signin") {
|
||||
return await provider.signin(request, this);
|
||||
return await provider.signin(event, this);
|
||||
} else {
|
||||
return await this.handleProviderCallback(request, provider);
|
||||
return await this.handleProviderCallback(event, provider);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -190,13 +188,13 @@ export class Auth {
|
||||
};
|
||||
}
|
||||
|
||||
get: RequestHandler = async (request) => {
|
||||
const { url } = request;
|
||||
get: RequestHandler = async (event: RequestEvent): Promise<any> => {
|
||||
const { url } = event;
|
||||
|
||||
if (url.pathname === this.getPath("csrf")) {
|
||||
return { body: "1234" }; // TODO: Generate real token
|
||||
} else if (url.pathname === this.getPath("session")) {
|
||||
const session = await this.getSession(request);
|
||||
const session = await this.getSession(event);
|
||||
return {
|
||||
body: {
|
||||
session,
|
||||
@ -204,15 +202,16 @@ export class Auth {
|
||||
};
|
||||
}
|
||||
|
||||
return await this.handleEndpoint(request);
|
||||
return await this.handleEndpoint(event);
|
||||
};
|
||||
|
||||
post: RequestHandler = async (request) => {
|
||||
return await this.handleEndpoint(request);
|
||||
post: RequestHandler = async (event: RequestEvent) => {
|
||||
return await this.handleEndpoint(event);
|
||||
};
|
||||
|
||||
getSession: GetSession = async ({ headers }) => {
|
||||
const token = await this.getToken(headers);
|
||||
getSession: GetSession = async (event: RequestEvent) => {
|
||||
const { request } = event;
|
||||
const token = await this.getToken(request.headers);
|
||||
|
||||
if (token) {
|
||||
if (this.config?.callbacks?.session) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
import type { EndpointOutput } from "@sveltejs/kit";
|
||||
import { ServerRequest } from "@sveltejs/kit/types/hooks";
|
||||
import { RequestEvent } from "@sveltejs/kit/types/hooks";
|
||||
import type { Auth } from "../auth";
|
||||
import type { CallbackResult } from "../types";
|
||||
|
||||
@ -28,12 +28,12 @@ export abstract class Provider<T extends ProviderConfig = ProviderConfig> {
|
||||
}
|
||||
|
||||
abstract signin<Locals extends Record<string, any> = Record<string, any>, Body = unknown>(
|
||||
request: ServerRequest<Locals, Body>,
|
||||
event: RequestEvent,
|
||||
svelteKitAuth: Auth,
|
||||
): EndpointOutput | Promise<EndpointOutput>;
|
||||
|
||||
abstract callback<Locals extends Record<string, any> = Record<string, any>, Body = unknown>(
|
||||
request: ServerRequest<Locals, Body>,
|
||||
event: RequestEvent,
|
||||
svelteKitAuth: Auth,
|
||||
): CallbackResult | Promise<CallbackResult>;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
import type { EndpointOutput } from "@sveltejs/kit/types/endpoint";
|
||||
import { ServerRequest } from "@sveltejs/kit/types/hooks";
|
||||
import { RequestEvent } from "@sveltejs/kit/types/hooks";
|
||||
import type { Auth } from "../auth";
|
||||
import type { CallbackResult } from "../types";
|
||||
import { Provider, ProviderConfig } from "./base";
|
||||
@ -25,7 +25,7 @@ export abstract class OAuth2BaseProvider<
|
||||
T extends OAuth2BaseProviderConfig,
|
||||
> extends Provider<T> {
|
||||
abstract getAuthorizationUrl(
|
||||
request: ServerRequest,
|
||||
event: RequestEvent,
|
||||
auth: Auth,
|
||||
state: string,
|
||||
nonce: string,
|
||||
@ -33,14 +33,15 @@ export abstract class OAuth2BaseProvider<
|
||||
abstract getTokens(code: string, redirectUri: string): TokensType | Promise<TokensType>;
|
||||
abstract getUserProfile(tokens: any): ProfileType | Promise<ProfileType>;
|
||||
|
||||
async signin(request: ServerRequest, auth: Auth): Promise<EndpointOutput> {
|
||||
const { method, url } = request;
|
||||
async signin(event: RequestEvent, auth: Auth): Promise<EndpointOutput> {
|
||||
const { method } = event.request;
|
||||
const { url } = event;
|
||||
const state = [
|
||||
`redirect=${url.searchParams.get("redirect") ?? this.getUri(auth, "/", url.host)}`,
|
||||
].join(",");
|
||||
const base64State = Buffer.from(state).toString("base64");
|
||||
const nonce = Math.round(Math.random() * 1000).toString(); // TODO: Generate random based on user values
|
||||
const authUrl = await this.getAuthorizationUrl(request, auth, base64State, nonce);
|
||||
const authUrl = await this.getAuthorizationUrl(event, auth, base64State, nonce);
|
||||
|
||||
if (method === "POST") {
|
||||
return {
|
||||
@ -68,7 +69,8 @@ export abstract class OAuth2BaseProvider<
|
||||
}
|
||||
}
|
||||
|
||||
async callback({ url }: ServerRequest, auth: Auth): Promise<CallbackResult> {
|
||||
async callback(event: RequestEvent, auth: Auth): Promise<any> {
|
||||
const { request, url } = event;
|
||||
const code = url.searchParams.get("code");
|
||||
const redirect = this.getStateValue(url.searchParams, "redirect");
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { ServerRequest } from "@sveltejs/kit/types/hooks";
|
||||
import { RequestEvent } from "@sveltejs/kit/types/hooks";
|
||||
import type { Auth } from "../auth";
|
||||
import { ucFirst } from "../helpers";
|
||||
import { OAuth2BaseProvider, OAuth2BaseProviderConfig, OAuth2Tokens } from "./oauth2.base";
|
||||
@ -37,7 +37,7 @@ export class OAuth2Provider<
|
||||
});
|
||||
}
|
||||
|
||||
getAuthorizationUrl({ url }: ServerRequest, auth: Auth, state: string, nonce: string) {
|
||||
getAuthorizationUrl({ url }: RequestEvent, auth: Auth, state: string, nonce: string) {
|
||||
const data = {
|
||||
state,
|
||||
nonce,
|
||||
|
@ -1,5 +1,4 @@
|
||||
import { OAuth2Provider, OAuth2ProviderConfig } from "./oauth2";
|
||||
import type { ProfileCallback } from "./oauth2.base";
|
||||
|
||||
export interface RedditProfile {
|
||||
is_employee: boolean;
|
||||
|
@ -1,6 +1,5 @@
|
||||
import { ServerRequest } from "@sveltejs/kit/types/hooks";
|
||||
import { RequestEvent } from "@sveltejs/kit/types/hooks";
|
||||
import type { Auth } from "../auth";
|
||||
import type { CallbackResult } from "../types";
|
||||
import { OAuth2BaseProvider, OAuth2BaseProviderConfig } from "./oauth2.base";
|
||||
|
||||
interface TwitterAuthProviderConfig extends OAuth2BaseProviderConfig {
|
||||
@ -38,7 +37,7 @@ export class TwitterAuthProvider extends OAuth2BaseProvider<any, any, TwitterAut
|
||||
};
|
||||
}
|
||||
|
||||
async getAuthorizationUrl({ url }: ServerRequest, auth: Auth, state: string, nonce: string) {
|
||||
async getAuthorizationUrl({ url }: RequestEvent, auth: Auth, state: string, nonce: string) {
|
||||
const endpoint = "https://api.twitter.com/oauth/authorize";
|
||||
|
||||
const { oauthToken } = await this.getRequestToken(auth, url.host);
|
||||
@ -71,7 +70,8 @@ export class TwitterAuthProvider extends OAuth2BaseProvider<any, any, TwitterAut
|
||||
return await res.json();
|
||||
}
|
||||
|
||||
async callback({ url }: ServerRequest, auth: Auth): Promise<CallbackResult> {
|
||||
async callback(event: RequestEvent, auth: Auth): Promise<any> {
|
||||
const { url } = event;
|
||||
const oauthToken = url.searchParams.get("oauth_token");
|
||||
const oauthVerifier = url.searchParams.get("oauth_verifier");
|
||||
const redirect = this.getStateValue(url.searchParams, "redirect");
|
||||
|
Loading…
Reference in New Issue
Block a user