svelte.sk-auth/src/providers/reddit.ts
Dan6erbond 5d1802fea4
[ENHANCEMENT] Demo / Testing App, Updated Build Configuration (#8)
* 🎉 Scaffold example app with SvelteKit barebones skeleton

* 💄 Add TWCSS and base styles with fonts Inter/Fira Mono

* 🔧 Add `exports` and `types` to `package.json` and update `tsconfig.json` for Vite-compatible build output

*  Add local dependency to `svelte-kit-auth` as symlink

* 🔧 Update example app env variables

*  Add basic auth config to example app

* ♻️ Export all providers from `/providers` module

* 🎨 Make `Auth` class default export of lib

* 🚚 Rename `example-app` to `app`

*  Use `file:` instead of `link:` for local dependency to `svelte-kit-auth`

* 🔧 Add `JWT_SECRET_KEY` to env and config

* 🎨 Add `RedditOAuthProvider.profileHandler` for general use and stripping of payload

*  Export auth API routes from app

* ⬆️ Update local deps

*  Add `host` and `basePath` to general config and improve recognition of routes

* 🚨 Exclude `app` from TS build

* 📌 Undo `file:` mapping dependency for usage with Vite

TODO: Needs to be fixed for release.

* 🎨 Enable TS `strict` mode and set target to `es2017`

* 📌 Undo `file:` mapping dependency for usage with Vite

* 🚨 Format and lint files

* 🍱 Add logo

*  Add login and profile routes to example app for showcase and testing

* 💄 Add PrismJS and create homepage with example

* 🔨 Add `build:watch`
2021-05-21 17:59:21 +02:00

124 lines
2.7 KiB
TypeScript

import type { ServerRequest } from "@sveltejs/kit/types/endpoint";
import { OAuth2Provider, OAuth2ProviderConfig } from "./oauth2";
interface RedditOAuthProviderConfig extends OAuth2ProviderConfig {
apiKey: string;
apiSecret: string;
scope?: string;
duration?: "temporary" | "permanent";
}
const redditProfileHandler = ({
is_employee,
has_external_account,
snoovatar_img,
verified,
id,
over_18,
is_gold,
is_mod,
awarder_karma,
has_verified_email,
is_suspended,
icon_img,
pref_nightmode,
awardee_karma,
password_set,
link_karma,
total_karma,
name,
created,
created_utc,
comment_karma,
}) => ({
is_employee,
has_external_account,
snoovatar_img,
verified,
id,
over_18,
is_gold,
is_mod,
awarder_karma,
has_verified_email,
is_suspended,
icon_img,
pref_nightmode,
awardee_karma,
password_set,
link_karma,
total_karma,
name,
created,
created_utc,
comment_karma,
});
const defaultConfig: Partial<RedditOAuthProviderConfig> = {
id: "reddit",
scope: "identity",
duration: "temporary",
profile: redditProfileHandler,
};
export class RedditOAuthProvider extends OAuth2Provider<RedditOAuthProviderConfig> {
constructor(config: RedditOAuthProviderConfig) {
super({
...defaultConfig,
...config,
});
}
static profileHandler = redditProfileHandler;
async getSigninUrl({ host }: ServerRequest, state: string) {
const endpoint = "https://www.reddit.com/api/v1/authorize";
const data = {
client_id: this.config.apiKey,
response_type: "code",
state,
redirect_uri: this.getCallbackUri(host),
duration: this.config.duration!,
scope: this.config.scope!,
};
const url = `${endpoint}?${new URLSearchParams(data)}`;
return url;
}
async getTokens(code: string, redirectUri: string) {
const endpoint = "https://www.reddit.com/api/v1/access_token";
const data = {
code,
redirect_uri: redirectUri,
grant_type: "authorization_code",
};
const body = Object.entries(data)
.map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`)
.join("&");
const res = await fetch(endpoint, {
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded",
Authorization:
"Basic " +
Buffer.from(`${this.config.apiKey}:${this.config.apiSecret}`).toString("base64"),
},
body,
});
return await res.json();
}
async getUserProfile(tokens: any) {
const endpoint = "https://oauth.reddit.com/api/v1/me";
const res = await fetch(endpoint, {
headers: { Authorization: `${tokens.token_type} ${tokens.access_token}` },
});
return await res.json();
}
}