mirror of
https://github.com/Dan6erbond/sk-auth.git
synced 2024-11-29 19:07:51 +01:00
feat: spotify provider (#60)
* feat: add spotify oauth2 provider * feat: add spotify oauth2 provider * feat: add spotify oauth2 provider * feat: add spotify oauth2 provider * feat: add spotify oauth2 provider * feat: add spotify oauth2 provider * feat: add spotify oauth2 provider * feat: add spotify oauth2 provider * feat: add spotify oauth2 provider * 🔧 Add `README.md` to `.prettierignore` * 🎨 Update Prettier and ESLint + format codebase * 💚 Use `--frozen-lockfile` flag in `yarn install` GitHub CI * 🔧 Ignore app dir in ESLint script * 🔧 Move ESLint ignore instructions to `.eslintignore` file * 🔧 Fix various glob patterns to properly ignore dirs * 🎨 Run Prettier Co-authored-by: Alexander Staroselsky <Alexander.Staroselsky1@T-Mobile.com> Co-authored-by: Dan6erbond <moravrav@gmail.com>
This commit is contained in:
parent
9a5dbe2386
commit
962064eb48
3
.eslintignore
Normal file
3
.eslintignore
Normal file
@ -0,0 +1,3 @@
|
||||
README.md
|
||||
app/
|
||||
*.cjs
|
21
.eslintrc-shared.cjs
Normal file
21
.eslintrc-shared.cjs
Normal file
@ -0,0 +1,21 @@
|
||||
module.exports = {
|
||||
root: true,
|
||||
parser: "@typescript-eslint/parser",
|
||||
extends: ["prettier"],
|
||||
plugins: ["@typescript-eslint"],
|
||||
parserOptions: {
|
||||
sourceType: "module",
|
||||
ecmaVersion: 2019,
|
||||
},
|
||||
env: {
|
||||
browser: true,
|
||||
es2017: true,
|
||||
node: true,
|
||||
},
|
||||
rules: {
|
||||
"@typescript-eslint/explicit-module-boundary-types": "off",
|
||||
"@typescript-eslint/no-explicit-any": "off",
|
||||
"@typescript-eslint/no-unused-vars": ["off", { argsIgnorePattern: "^_" }],
|
||||
"@typescript-eslint/no-non-null-assertion": "off",
|
||||
},
|
||||
};
|
@ -1,22 +1,9 @@
|
||||
module.exports = {
|
||||
root: true,
|
||||
parser: "@typescript-eslint/parser",
|
||||
extends: ["eslint:recommended", "plugin:@typescript-eslint/recommended", "prettier"],
|
||||
plugins: ["@typescript-eslint"],
|
||||
ignorePatterns: ["*.cjs", "app/**/*"],
|
||||
parserOptions: {
|
||||
sourceType: "module",
|
||||
ecmaVersion: 2019,
|
||||
},
|
||||
rules: {
|
||||
"@typescript-eslint/explicit-module-boundary-types": "off",
|
||||
"@typescript-eslint/no-explicit-any": "off",
|
||||
"@typescript-eslint/no-unused-vars": ["off", { argsIgnorePattern: "^_" }],
|
||||
"@typescript-eslint/no-non-null-assertion": "off",
|
||||
},
|
||||
env: {
|
||||
browser: true,
|
||||
es2017: true,
|
||||
node: true,
|
||||
},
|
||||
extends: [
|
||||
"eslint:recommended",
|
||||
"plugin:@typescript-eslint/recommended",
|
||||
"./.eslintrc-shared.cjs",
|
||||
],
|
||||
};
|
||||
|
7
.github/workflows/lint-on-pr.yml
vendored
7
.github/workflows/lint-on-pr.yml
vendored
@ -15,9 +15,6 @@ jobs:
|
||||
- uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 14
|
||||
- run: yarn install
|
||||
- run: yarn lint
|
||||
- run: yarn install
|
||||
working-directory: app
|
||||
- run: yarn lint
|
||||
- run: yarn install --frozen-lockfile && yarn lint
|
||||
- run: yarn install --frozen-lockfile && yarn lint
|
||||
working-directory: app
|
||||
|
2
.github/workflows/npm-publish.yml
vendored
2
.github/workflows/npm-publish.yml
vendored
@ -12,7 +12,7 @@ jobs:
|
||||
- uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 14
|
||||
- run: yarn install
|
||||
- run: yarn install --frozen-lockfile
|
||||
- run: yarn build
|
||||
- uses: JS-DevTools/npm-publish@v1
|
||||
with:
|
||||
|
@ -1,2 +1,4 @@
|
||||
dist/**
|
||||
node_modules/**
|
||||
dist/
|
||||
node_modules/
|
||||
README.md
|
||||
app/
|
||||
|
@ -31,7 +31,7 @@ SvelteKitAuth also comes with first-class support for Typescript out of the box,
|
||||
|
||||
SvelteKitAuth is very easy to setup! All you need to do is instantiate the `SvelteKitAuth` class, and configure it with some default providers, as well as a JWT secret key used to verify the cookies:
|
||||
|
||||
_**Warning**: env variables prefixed with `VITE_` can be exposed and leaked into client-side bundles if they are referenced in any client-side code. Make sure this is not the case, or consider using an alternative method such as loading them via dotenv directly instead.\_
|
||||
***Warning**: env variables prefixed with `VITE_` can be exposed and leaked into client-side bundles if they are referenced in any client-side code. Make sure this is not the case, or consider using an alternative method such as loading them via dotenv directly instead.*
|
||||
|
||||
```ts
|
||||
export const appAuth = new SvelteKitAuth({
|
||||
|
2
app/.eslintignore
Normal file
2
app/.eslintignore
Normal file
@ -0,0 +1,2 @@
|
||||
README.md
|
||||
*.cjs
|
@ -1,20 +1,15 @@
|
||||
module.exports = {
|
||||
root: true,
|
||||
parser: "@typescript-eslint/parser",
|
||||
extends: ["../.eslintrc.cjs"],
|
||||
plugins: ["svelte3", "@typescript-eslint"],
|
||||
ignorePatterns: ["*.cjs"],
|
||||
overrides: [{ files: ["*.svelte"], processor: "svelte3/svelte3" }],
|
||||
extends: ["../.eslintrc-shared.cjs"],
|
||||
plugins: ["svelte3"],
|
||||
overrides: [
|
||||
{
|
||||
files: ["*.svelte"],
|
||||
processor: "svelte3/svelte3",
|
||||
},
|
||||
],
|
||||
settings: {
|
||||
"svelte3/typescript": () => require("typescript"),
|
||||
},
|
||||
parserOptions: {
|
||||
sourceType: "module",
|
||||
ecmaVersion: 2019,
|
||||
},
|
||||
env: {
|
||||
browser: true,
|
||||
es2017: true,
|
||||
node: true,
|
||||
},
|
||||
};
|
||||
|
@ -1,4 +1,4 @@
|
||||
.svelte-kit/**
|
||||
static/**
|
||||
build/**
|
||||
node_modules/**
|
||||
.svelte-kit/
|
||||
static/
|
||||
build/
|
||||
node_modules/
|
||||
|
@ -5,7 +5,7 @@
|
||||
"dev": "svelte-kit dev",
|
||||
"build": "svelte-kit build",
|
||||
"preview": "svelte-kit preview",
|
||||
"lint": "prettier --check --plugin-search-dir=. . && eslint --ignore-path .gitignore --config .eslintrc.cjs .",
|
||||
"lint": "prettier --check --plugin-search-dir=. . && eslint .",
|
||||
"format": "prettier --write --plugin-search-dir=. ."
|
||||
},
|
||||
"devDependencies": {
|
||||
@ -33,6 +33,7 @@
|
||||
"dependencies": {
|
||||
"@fontsource/fira-mono": "^4.3.0",
|
||||
"@fontsource/inter": "^4.3.0",
|
||||
"clipboard": "^2.0.8",
|
||||
"clsx": "^1.1.1",
|
||||
"prismjs": "^1.23.0",
|
||||
"sk-auth": "file:../"
|
||||
|
2
app/src/global.d.ts
vendored
2
app/src/global.d.ts
vendored
@ -11,5 +11,7 @@ interface ImportMetaEnv {
|
||||
VITE_TWITTER_API_SECRET: string;
|
||||
VITE_REDDIT_API_KEY: string;
|
||||
VITE_REDDIT_API_SECRET: string;
|
||||
VITE_SPOTIFY_CLIENT_ID: string;
|
||||
VITE_SPOTIFY_CLIENT_SECRET: string;
|
||||
VITE_JWT_SECRET_KEY: string;
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ import {
|
||||
GoogleOAuth2Provider,
|
||||
RedditOAuth2Provider,
|
||||
TwitterAuthProvider,
|
||||
SpotifyOAuth2Provider,
|
||||
} from "sk-auth/providers";
|
||||
|
||||
export const appAuth = new SvelteKitAuth({
|
||||
@ -45,6 +46,13 @@ export const appAuth = new SvelteKitAuth({
|
||||
return { ...slim, provider: "reddit" };
|
||||
},
|
||||
}),
|
||||
new SpotifyOAuth2Provider({
|
||||
clientId: import.meta.env.VITE_SPOTIFY_CLIENT_ID,
|
||||
clientSecret: import.meta.env.VITE_SPOTIFY_CLIENT_SECRET,
|
||||
profile(profile) {
|
||||
return { ...profile, provider: "spotify" };
|
||||
},
|
||||
}),
|
||||
],
|
||||
callbacks: {
|
||||
jwt(token, profile) {
|
||||
|
@ -180,6 +180,38 @@
|
||||
<span>Sign in with Reddit</span>
|
||||
</a>
|
||||
|
||||
<a
|
||||
href="/api/auth/signin/spotify?redirect=/profile"
|
||||
class={clsx(
|
||||
"text-sm",
|
||||
"md:text-base",
|
||||
"inline-flex",
|
||||
"space-x-4",
|
||||
"py-2",
|
||||
"px-4",
|
||||
"border-gray-400",
|
||||
"rounded",
|
||||
"hover:no-underline",
|
||||
"border",
|
||||
"hover:bg-gray-100",
|
||||
"transition-colors",
|
||||
"items-center",
|
||||
)}
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
version="1.1"
|
||||
viewBox="0 0 168 168"
|
||||
class={clsx("h-4", "w-4", "md:h-6", "md:w-6")}
|
||||
>
|
||||
<path
|
||||
fill="#1ED760"
|
||||
d="m83.996 0.277c-46.249 0-83.743 37.493-83.743 83.742 0 46.251 37.494 83.741 83.743 83.741 46.254 0 83.744-37.49 83.744-83.741 0-46.246-37.49-83.738-83.745-83.738l0.001-0.004zm38.404 120.78c-1.5 2.46-4.72 3.24-7.18 1.73-19.662-12.01-44.414-14.73-73.564-8.07-2.809 0.64-5.609-1.12-6.249-3.93-0.643-2.81 1.11-5.61 3.926-6.25 31.9-7.291 59.263-4.15 81.337 9.34 2.46 1.51 3.24 4.72 1.73 7.18zm10.25-22.805c-1.89 3.075-5.91 4.045-8.98 2.155-22.51-13.839-56.823-17.846-83.448-9.764-3.453 1.043-7.1-0.903-8.148-4.35-1.04-3.453 0.907-7.093 4.354-8.143 30.413-9.228 68.222-4.758 94.072 11.127 3.07 1.89 4.04 5.91 2.15 8.976v-0.001zm0.88-23.744c-26.99-16.031-71.52-17.505-97.289-9.684-4.138 1.255-8.514-1.081-9.768-5.219-1.254-4.14 1.08-8.513 5.221-9.771 29.581-8.98 78.756-7.245 109.83 11.202 3.73 2.209 4.95 7.016 2.74 10.733-2.2 3.722-7.02 4.949-10.73 2.739z"
|
||||
/>
|
||||
</svg>
|
||||
<span>Sign in with Spotify</span>
|
||||
</a>
|
||||
|
||||
<p class={clsx("text-gray-600", "text-center", "border-gray-400", "border-b", "pb-2")}>
|
||||
Coming soon.
|
||||
</p>
|
||||
|
@ -201,6 +201,47 @@
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
<div class={clsx("flex", "items-center", "space-x-4")}>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
version="1.1"
|
||||
viewBox="0 0 168 168"
|
||||
class={clsx("h-4", "w-4", "md:h-6", "md:w-6")}
|
||||
>
|
||||
<path
|
||||
fill="#1ED760"
|
||||
d="m83.996 0.277c-46.249 0-83.743 37.493-83.743 83.742 0 46.251 37.494 83.741 83.743 83.741 46.254 0 83.744-37.49 83.744-83.741 0-46.246-37.49-83.738-83.745-83.738l0.001-0.004zm38.404 120.78c-1.5 2.46-4.72 3.24-7.18 1.73-19.662-12.01-44.414-14.73-73.564-8.07-2.809 0.64-5.609-1.12-6.249-3.93-0.643-2.81 1.11-5.61 3.926-6.25 31.9-7.291 59.263-4.15 81.337 9.34 2.46 1.51 3.24 4.72 1.73 7.18zm10.25-22.805c-1.89 3.075-5.91 4.045-8.98 2.155-22.51-13.839-56.823-17.846-83.448-9.764-3.453 1.043-7.1-0.903-8.148-4.35-1.04-3.453 0.907-7.093 4.354-8.143 30.413-9.228 68.222-4.758 94.072 11.127 3.07 1.89 4.04 5.91 2.15 8.976v-0.001zm0.88-23.744c-26.99-16.031-71.52-17.505-97.289-9.684-4.138 1.255-8.514-1.081-9.768-5.219-1.254-4.14 1.08-8.513 5.221-9.771 29.581-8.98 78.756-7.245 109.83 11.202 3.73 2.209 4.95 7.016 2.74 10.733-2.2 3.722-7.02 4.949-10.73 2.739z"
|
||||
/>
|
||||
</svg>
|
||||
<div class={clsx("flex", "flex-col", "items-start", "space-y-1")}>
|
||||
{#if $session.user.connections.spotify}
|
||||
<p class={clsx("font-bold")}>Signed in as:</p>
|
||||
|
||||
{$session.user.connections.spotify.display_name}
|
||||
{:else}
|
||||
<p class={clsx("font-bold")}>Not signed in</p>
|
||||
<div
|
||||
class={clsx(
|
||||
"text-xs",
|
||||
"md:text-sm",
|
||||
"py-1",
|
||||
"px-2",
|
||||
"border-gray-400",
|
||||
"rounded",
|
||||
"hover:no-underline",
|
||||
"border",
|
||||
"hover:bg-gray-100",
|
||||
"transition-colors",
|
||||
"items-center",
|
||||
"cursor-not-allowed",
|
||||
"inline-block",
|
||||
)}
|
||||
>
|
||||
Connect
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class={clsx("text-lg", "mb-2")}>Session</p>
|
||||
|
@ -1467,7 +1467,7 @@ chokidar@^3.5.1:
|
||||
optionalDependencies:
|
||||
fsevents "~2.3.1"
|
||||
|
||||
clipboard@^2.0.0:
|
||||
clipboard@^2.0.0, clipboard@^2.0.8:
|
||||
version "2.0.8"
|
||||
resolved "https://registry.yarnpkg.com/clipboard/-/clipboard-2.0.8.tgz#ffc6c103dd2967a83005f3f61976aa4655a4cdba"
|
||||
integrity sha512-Y6WO0unAIQp5bLmk1zdThRhgJt/x3ks6f30s3oE3H1mgIEU33XyQjEf8gsf6DxC7NPX8Y1SsNWjUjL/ywLnnbQ==
|
||||
|
@ -21,7 +21,7 @@
|
||||
"build": "rollup --config",
|
||||
"dev": "rollup --config --watch",
|
||||
"test": "echo \"Error: no test specified\" && exit 1",
|
||||
"lint": "prettier --check --plugin-search-dir=. . && eslint --ignore-path .gitignore .",
|
||||
"lint": "prettier --check --plugin-search-dir=. . && eslint .",
|
||||
"format": "prettier --write --plugin-search-dir=. ."
|
||||
},
|
||||
"keywords": [
|
||||
|
@ -1,9 +1,8 @@
|
||||
export { Provider } from "./base";
|
||||
export { TwitchOAuth2Provider } from "./twitch";
|
||||
export type { TwitchProfile, TwitchTokens } from "./twitch";
|
||||
export { GitHubOAuth2Provider } from "./github";
|
||||
export type { GitHubProfile, GitHubTokens } from "./github";
|
||||
export { GoogleOAuth2Provider } from "./google";
|
||||
export type { GoogleProfile, GoogleTokens } from "./google";
|
||||
export { TwitterAuthProvider } from "./twitter";
|
||||
export { FacebookOAuth2Provider } from "./facebook";
|
||||
export type { FacebookProfile, FacebookTokens } from "./facebook";
|
||||
export { OAuth2BaseProvider } from "./oauth2.base";
|
||||
@ -11,5 +10,8 @@ export type { ProfileCallback } from "./oauth2.base";
|
||||
export { OAuth2Provider } from "./oauth2";
|
||||
export { RedditOAuth2Provider } from "./reddit";
|
||||
export type { RedditProfile, RedditTokens } from "./reddit";
|
||||
export { GitHubOAuth2Provider } from "./github";
|
||||
export type { GitHubProfile, GitHubTokens } from "./github";
|
||||
export { SpotifyOAuth2Provider } from "./spotify";
|
||||
export type { SpotifyProfile, SpotifyTokens } from "./spotify";
|
||||
export { TwitchOAuth2Provider } from "./twitch";
|
||||
export type { TwitchProfile, TwitchTokens } from "./twitch";
|
||||
export { TwitterAuthProvider } from "./twitter";
|
||||
|
73
src/providers/spotify.ts
Normal file
73
src/providers/spotify.ts
Normal file
@ -0,0 +1,73 @@
|
||||
import { OAuth2Provider, OAuth2ProviderConfig } from "./oauth2";
|
||||
|
||||
export interface SpotifyProfile {
|
||||
display_name: string;
|
||||
email: string;
|
||||
external_urls: SpotifyProfileExternalUrls;
|
||||
followers: SpotifyProfileFollowers;
|
||||
href: string;
|
||||
id: string;
|
||||
images: SpotifyProfileImage[];
|
||||
type: string;
|
||||
uri: string;
|
||||
// This field is only available when the current user has granted access to the user-read-private scope.
|
||||
explicit_content?: SpotifyExplicitContent;
|
||||
// This field is only available when the current user has granted access to the user-read-private scope.
|
||||
product?: string;
|
||||
// This field is only available when the current user has granted access to the user-read-private scope.
|
||||
country?: string;
|
||||
}
|
||||
|
||||
export interface SpotifyExplicitContent {
|
||||
filter_enabled: boolean;
|
||||
filter_locked: boolean;
|
||||
}
|
||||
|
||||
export interface SpotifyProfileImage {
|
||||
height: number;
|
||||
url: string;
|
||||
width: string;
|
||||
}
|
||||
|
||||
export interface SpotifyProfileFollowers {
|
||||
href: string;
|
||||
total: number;
|
||||
}
|
||||
|
||||
export interface SpotifyProfileExternalUrls {
|
||||
spotify: string;
|
||||
}
|
||||
|
||||
export interface SpotifyTokens {
|
||||
access_token: string;
|
||||
token_type: string;
|
||||
expires_in: number;
|
||||
refresh_token: string;
|
||||
scope: string;
|
||||
}
|
||||
|
||||
interface SpotifyOAuth2ProviderConfig extends OAuth2ProviderConfig<SpotifyProfile, SpotifyTokens> {
|
||||
show_dialog: boolean;
|
||||
}
|
||||
|
||||
const defaultConfig: Partial<SpotifyOAuth2ProviderConfig> = {
|
||||
id: "spotify",
|
||||
scope: "user-read-email",
|
||||
accessTokenUrl: "https://accounts.spotify.com/api/token",
|
||||
authorizationUrl: "https://accounts.spotify.com/authorize",
|
||||
profileUrl: "https://api.spotify.com/v1/me",
|
||||
contentType: "application/x-www-form-urlencoded",
|
||||
};
|
||||
|
||||
export class SpotifyOAuth2Provider extends OAuth2Provider<
|
||||
SpotifyProfile,
|
||||
SpotifyTokens,
|
||||
SpotifyOAuth2ProviderConfig
|
||||
> {
|
||||
constructor(config: SpotifyOAuth2ProviderConfig) {
|
||||
super({
|
||||
...defaultConfig,
|
||||
...config,
|
||||
});
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user