Skip to content
This repository has been archived by the owner on Sep 22, 2024. It is now read-only.

Commit

Permalink
fix(plugins/auth): simplify getAuthConfig utility by removing confi…
Browse files Browse the repository at this point in the history
…g as parameter
  • Loading branch information
miguelrk committed May 21, 2024
1 parent 70040eb commit d2c5232
Show file tree
Hide file tree
Showing 14 changed files with 97 additions and 224 deletions.
8 changes: 4 additions & 4 deletions lib/plugins/auth/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ import {
} from "./middlewares/mod.ts";
import createAuth from "./routes/auth.tsx";
import { getRoutesByProvider } from "./routes/mod.ts";
import type { EmailClientConfig } from "./utils/providers/email.ts";
import type { NetzoClientConfig } from "./utils/providers/netzo.ts";
import type { EmailAuthConfig } from "./utils/providers/email.ts";
import type { NetzoAuthConfig } from "./utils/providers/netzo.ts";
import type { Auth, AuthProvider, AuthUser } from "./utils/types.ts";

export * from "../../deps/deno_kv_oauth/mod.ts";
Expand All @@ -29,8 +29,8 @@ export type AuthConfig = {
image?: React.ImgHTMLAttributes<HTMLImageElement>;
locale?: "en" | "es";
providers: {
netzo?: NetzoClientConfig;
email?: EmailClientConfig;
netzo?: NetzoAuthConfig;
email?: EmailAuthConfig;
google?: OAuth2ClientConfig;
github?: OAuth2ClientConfig;
gitlab?: OAuth2ClientConfig;
Expand Down
6 changes: 3 additions & 3 deletions lib/plugins/auth/routes/mod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,22 +11,22 @@ export const getRoutesByProvider = (
provider: AuthProvider,
options: AuthConfig,
): PluginRoute[] => {
const providerOptions = options.providers?.[provider] ?? {};
const _providerOptions = options.providers?.[provider] ?? {};
const [signIn, handleCallback, signOut] = getFunctionsByProvider(provider);

const routes: PluginRoute[] = [
{
path: `/auth/${provider}/signin`,
handler: async (req, ctx) => {
const authConfig = getAuthConfig(provider, providerOptions, ctx);
const authConfig = getAuthConfig(provider, ctx);
const response = await signIn(req, authConfig);
return response;
},
},
{
path: `/auth/${provider}/callback`,
handler: async (req, ctx) => {
const authConfig = getAuthConfig(provider, providerOptions, ctx);
const authConfig = getAuthConfig(provider, ctx);
const {
response,
tokens,
Expand Down
14 changes: 0 additions & 14 deletions lib/plugins/auth/utils/providers/auth0.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,5 @@
import { createAuth0OAuthConfig } from "../../../../deps/deno_kv_oauth/mod.ts";
import type { AuthUserFromProvider } from "../types.ts";

export { createAuth0OAuthConfig };

export function isAuth0Setup(
options: Parameters<typeof createAuth0OAuthConfig>[0],
) {
try {
createAuth0OAuthConfig(options);
return true;
} catch {
return false;
}
}

export type UserAuth0 = {
sub: string;
nickname: string;
Expand Down
36 changes: 17 additions & 19 deletions lib/plugins/auth/utils/providers/email.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { handleCallback, signIn } from "../../../../deps/deno_kv_oauth/mod.ts";
import type { AuthUserFromProvider } from "../types.ts";

type UserEmail = {
Expand All @@ -7,35 +8,32 @@ type UserEmail = {
avatar: string;
};

export type EmailClientConfig = Record<string | number | symbol, never>; // (empty object)

export const createEmailClientConfig = () => {
return {};
};

export function isEmailSetup() {
try {
createEmailClientConfig();
return true;
} catch {
return false;
}
}
export type EmailAuthConfig = Record<string | number | symbol, never>; // (empty object)

export async function signInEmail(
_req: Request,
_authConfig: ReturnType<typeof createEmailClientConfig>,
) {
_authConfig: EmailAuthConfig,
): ReturnType<typeof signIn> {
const response = await new Response("Not implemented");
return response;
}

export async function handleCallbackEmail(
_req: Request,
_authConfig: ReturnType<typeof createEmailClientConfig>,
) {
_authConfig: EmailAuthConfig,
): ReturnType<typeof handleCallback> {
const response = await new Response("Not implemented");
return response;
return {
response,
sessionId: `x-x-x-x-x`,
tokens: {
accessToken: "",
tokenType: "",
expiresIn: 0,
refreshToken: "",
scope: [],
},
};
}

export async function getUserEmail(
Expand Down
12 changes: 0 additions & 12 deletions lib/plugins/auth/utils/providers/github.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,5 @@
import { createGitHubOAuthConfig } from "../../../../deps/deno_kv_oauth/mod.ts";
import type { AuthUserFromProvider } from "../types.ts";

export { createGitHubOAuthConfig };

export function isGitHubSetup() {
try {
createGitHubOAuthConfig();
return true;
} catch {
return false;
}
}

export type UserGithub = {
login: string;
id: number;
Expand Down
14 changes: 0 additions & 14 deletions lib/plugins/auth/utils/providers/gitlab.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,5 @@
import { createGitLabOAuthConfig } from "../../../../deps/deno_kv_oauth/mod.ts";
import type { AuthUserFromProvider } from "../types.ts";

export { createGitLabOAuthConfig };

export function isGitlabSetup(
options: Parameters<typeof createGitLabOAuthConfig>[0],
) {
try {
createGitLabOAuthConfig(options);
return true;
} catch {
return false;
}
}

export type UserGitlab = {
id: number;
username: string;
Expand Down
14 changes: 0 additions & 14 deletions lib/plugins/auth/utils/providers/google.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,5 @@
import { createGoogleOAuthConfig } from "../../../../deps/deno_kv_oauth/mod.ts";
import type { AuthUserFromProvider } from "../types.ts";

export { createGoogleOAuthConfig };

export function isGoogleSetup(
options: Parameters<typeof createGoogleOAuthConfig>[0],
) {
try {
createGoogleOAuthConfig(options);
return true;
} catch {
return false;
}
}

export type UserGoogle = {
sub: string;
name: string;
Expand Down
124 changes: 47 additions & 77 deletions lib/plugins/auth/utils/providers/mod.ts
Original file line number Diff line number Diff line change
@@ -1,105 +1,75 @@
import { FreshContext } from "$fresh/server.ts";
import {
createAuth0OAuthConfig,
createGitHubOAuthConfig,
createGitLabOAuthConfig,
createGoogleOAuthConfig,
createOktaOAuthConfig,
createSlackOAuthConfig,
handleCallback,
signIn,
signOut,
} from "../../../../deps/deno_kv_oauth/mod.ts";
import type { AuthConfig } from "../../plugin.ts";
import type { AuthProvider, AuthUserFromProvider } from "../types.ts";
import { createAuth0OAuthConfig, getUserAuth0, isAuth0Setup } from "./auth0.ts";
import {
createEmailClientConfig,
getUserEmail,
handleCallbackEmail,
isEmailSetup,
signInEmail,
} from "./email.ts";
import {
createGitHubOAuthConfig,
getUserGithub,
isGitHubSetup,
} from "./github.ts";
import {
createGitLabOAuthConfig,
getUserGitlab,
isGitlabSetup,
} from "./gitlab.ts";
import {
createGoogleOAuthConfig,
getUserGoogle,
isGoogleSetup,
} from "./google.ts";
import {
createNetzoClientConfig,
getUserNetzo,
handleCallback as handleCallbackNetzo,
isNetzoSetup,
signIn as signInNetzo,
} from "./netzo.ts";
import { createOktaOAuthConfig, getUserOkta, isOktaSetup } from "./okta.ts";
import { createSlackOAuthConfig, getUserSlack, isSlackSetup } from "./slack.ts";

const setFromOptionsIfNotInEnv = (name: string, value: string) => {
if (!value) value = Deno.env.get(name)!;
Deno.env.set(name, value);
};

export const getAuthConfig = (
provider: AuthProvider,
options: AuthConfig["providers"][AuthProvider],
) => {
const getError = (provider: AuthProvider) =>
new Error(
`[auth] Missing or invalid configuration for "${provider}" provider`,
);
import { getUserAuth0 } from "./auth0.ts";
import { getUserEmail, handleCallbackEmail, signInEmail } from "./email.ts";
import { getUserGithub } from "./github.ts";
import { getUserGitlab } from "./gitlab.ts";
import { getUserGoogle } from "./google.ts";
import { getUserNetzo, handleCallbackNetzo, signInNetzo } from "./netzo.ts";
import { getUserOkta } from "./okta.ts";
import { getUserSlack } from "./slack.ts";

options.redirectUri = `/auth/${provider}/callback`;
export const getAuthConfig = (provider: AuthProvider, ctx: FreshContext) => {
const redirectUri = `${ctx.url.origin}/auth/${provider}/callback`;

switch (provider) {
case "netzo": {
if (!isNetzoSetup()) throw getError(provider);
return createNetzoClientConfig();
return {
projectId: Deno.env.get("NETZO_PROJECT_ID")!,
apiKey: Deno.env.get("NETZO_API_KEY")!,
}; // MUST be set if using Netzo Auth Provider
}
case "email": {
if (!isEmailSetup()) throw getError(provider);
return createEmailClientConfig();
return {};
}
case "google": {
setFromOptionsIfNotInEnv("GOOGLE_CLIENT_ID", options.clientId);
setFromOptionsIfNotInEnv("GOOGLE_CLIENT_SECRET", options.clientSecret);
options.scope ??= "https://www.googleapis.com/auth/userinfo.profile";
if (!isGoogleSetup(options)) throw getError(provider);
return createGoogleOAuthConfig(options);
return createGoogleOAuthConfig({
redirectUri,
scope: "https://www.googleapis.com/auth/userinfo.email",
});
}
case "github": {
setFromOptionsIfNotInEnv("GITHUB_CLIENT_ID", options.clientId);
setFromOptionsIfNotInEnv("GITHUB_CLIENT_SECRET", options.clientSecret);
if (!isGitHubSetup()) throw getError(provider);
return createGitHubOAuthConfig();
return createGitHubOAuthConfig({ redirectUri, scope: "user:email" });
}
case "gitlab": {
setFromOptionsIfNotInEnv("GITLAB_CLIENT_ID", options.clientId);
setFromOptionsIfNotInEnv("GITLAB_CLIENT_SECRET", options.clientSecret);
if (!isGitlabSetup(options)) throw getError(provider);
return createGitLabOAuthConfig(options);
return createGitLabOAuthConfig({ redirectUri, scope: "profile" });
}
case "slack": {
setFromOptionsIfNotInEnv("SLACK_CLIENT_ID", options.clientId);
setFromOptionsIfNotInEnv("SLACK_CLIENT_SECRET", options.clientSecret);
if (!isSlackSetup(options)) throw getError(provider);
return createSlackOAuthConfig(options);
return createSlackOAuthConfig({
redirectUri,
scope: "users.profile:read",
});
}
case "auth0": {
setFromOptionsIfNotInEnv("CUSTOM_CLIENT_ID", options.clientId);
setFromOptionsIfNotInEnv("CUSTOM_CLIENT_SECRET", options.clientSecret);
if (!isAuth0Setup(options)) throw getError(provider);
return createAuth0OAuthConfig(options);
return createAuth0OAuthConfig({
redirectUri,
scope: "openid email profile",
});
}
case "okta": {
setFromOptionsIfNotInEnv("OKTA_CLIENT_ID", options.clientId);
setFromOptionsIfNotInEnv("OKTA_CLIENT_SECRET", options.clientSecret);
if (!isOktaSetup(options)) throw getError(provider);
return createOktaOAuthConfig(options);
return createOktaOAuthConfig({
redirectUri,
scope: "openid email profile",
});
}
// case "aws-cognito":
// case "azure-ad":
// case "azure-adb2c":
// case "clerk":
// case "discord":
// case "dropbox":
// case "facebook":
default:
throw new Error(`Provider ${provider} not supported`);
}
Expand Down
23 changes: 10 additions & 13 deletions lib/plugins/auth/utils/providers/netzo.handle_callback.ts
Original file line number Diff line number Diff line change
@@ -1,27 +1,28 @@
// adapted from https://github.com/denoland/deno_kv_oauth/blob/main/lib/handle_callback.ts
import type { Tokens } from "../../../../deps/oauth2_client/src/types.ts";
import { getCookies, setCookie } from "../../../../deps/deno_kv_oauth/deps.ts";
import {
COOKIE_BASE,
OAUTH_COOKIE_NAME,
SITE_COOKIE_NAME,
getCookieName,
isHttps,
OAUTH_COOKIE_NAME,
redirect,
SITE_COOKIE_NAME,
} from "../../../../deps/deno_kv_oauth/lib/_http.ts";
import { getAndDeleteOAuthSession } from "../../../../deps/deno_kv_oauth/lib/_kv.ts";
import { NetzoClientConfig } from "./netzo.ts";
import { handleCallback } from "../../../../deps/deno_kv_oauth/mod.ts";
import type { Tokens } from "../../../../deps/oauth2_client/src/types.ts";
import { NetzoAuthConfig } from "./netzo.ts";

/**
* Handles the OAuth callback request for the given Netzo configuration, and
* then redirects the client to the success URL set in {@linkcode signIn}. The
* request URL must match the redirect URL of the OAuth application.
*/
export async function handleCallback(
export async function handleCallbackNetzo(
request: Request,
/** @see {@linkcode NetzoClientConfig} */
_clientConfig: NetzoClientConfig,
) {
/** @see {@linkcode NetzoAuthConfig} */
_clientConfig: NetzoAuthConfig,
): ReturnType<typeof handleCallback> {
const oauthCookieName = getCookieName(
OAUTH_COOKIE_NAME,
isHttps(request.url),
Expand Down Expand Up @@ -53,9 +54,5 @@ export async function handleCallback(
secure: isHttps(request.url),
},
);
return {
response,
sessionId,
tokens,
};
return { response, sessionId, tokens };
}
Loading

0 comments on commit d2c5232

Please sign in to comment.