Deno KV OAuth logo

High-level OAuth 2.0 powered by Deno KV.

Docs CI codecov

Deno KV OAuth (Beta)

Features

Live Demo

You can also check out a live demo at https://kv-oauth.deno.dev, which uses Github as the OAuth 2.0 provider. Source code is located in demo.ts.

Usage

Check out the full documentation and API reference here.

Getting Started with Fresh

Note: The minimum required version for plugins in Fresh is 1.3.0

If you're not performing anything special in the sign-in, sign-out and callback handlers, you can add the Fresh plugin to your project. This automatically handles GET /oauth/signin, GET /oauth/callback and GET /oauth/signout routes.

  1. Create your OAuth 2.0 application for your given provider.

  2. Create your pre-configured or custom OAuth 2.0 client instance.

    // utils/oauth2_client.ts
    import { createGitHubOAuth2Client } from "https://deno.land/x/deno_kv_oauth@$VERSION/mod.ts";
    
    const oauth2Client = createGitHubOAuth2Client();
  3. Configure Fresh to use the plugin.

    // main.ts
    import { start } from "$fresh/server.ts";
    import { kvOAuthPlugin } from "https://deno.land/x/deno_kv_oauth@$VERSION/fresh.ts";
    import manifest from "./fresh.gen.ts";
    import { oauth2Client } from "./utils/oauth2_client.ts";
    
    await start(manifest, {
      plugins: [
        kvOAuthPlugin(oauth2Client),
      ],
    });

If you require more advanced setups, you can create your own plugin. For more information, see:

Getting Started with Other Frameworks

This example uses GitHub as the OAuth 2.0 provider. However, you can use any provider you like.

  1. Create your OAuth 2.0 application for your given provider.

  2. Create your pre-configured or custom OAuth 2.0 client instance.

    // Pre-configured OAuth 2.0 client
    import { createGitHubOAuth2Client } from "https://deno.land/x/deno_kv_oauth@$VERSION/mod.ts";
    
    const oauth2Client = createGitHubOAuth2Client();
  3. Using the OAuth 2.0 client instance, insert the authentication flow functions into your authentication routes.

    // Sign-in, callback and sign-out handlers
    import {
      createGitHubOAuth2Client,
      handleCallback,
      signIn,
      signOut,
    } from "https://deno.land/x/deno_kv_oauth@$VERSION/mod.ts";
    
    const oauth2Client = createGitHubOAuth2Client();
    
    async function handleSignIn(request: Request) {
      return await signIn(request, oauth2Client);
    }
    
    async function handleOAuth2Callback(request: Request) {
      return await handleCallback(request, oauth2Client);
    }
    
    async function handleSignOut(request: Request) {
      return await signOut(request);
    }
  4. Use Deno KV OAuth's helper functions where needed.

    // Protected route
    import {
      createGitHubOAuth2Client,
      getSessionAccessToken,
      getSessionId,
    } from "https://deno.land/x/deno_kv_oauth@$VERSION/mod.ts";
    
    const oauth2Client = createGitHubOAuth2Client();
    
    async function getGitHubUser(accessToken: string): Promise<any> {
      const response = await fetch("https://api.github.com/user", {
        headers: { authorization: `Bearer ${accessToken}` },
      });
      if (!response.ok) {
        const { message } = await response.json();
        throw new Error(message);
      }
      return await response.json();
    }
    
    async function handleAccountPage(request: Request) {
      const sessionId = getSessionId(request);
      const hasSessionIdCookie = sessionId !== undefined;
    
      if (!hasSessionIdCookie) return new Response(null, { status: 404 });
    
      const accessToken = await getSessionAccessToken(oauth2Client, sessionId);
      if (accessToken === null) return new Response(null, { status: 400 });
    
      try {
        const githubUser = await getGitHubUser(accessToken);
        return Response.json(githubUser);
      } catch (error) {
        console.error(error);
        return Response.error();
      }
    }
  5. Start your server with the necessary environment variables.

    GITHUB_CLIENT_ID=xxx GITHUB_CLIENT_SECRET=xxx deno run --unstable --allow-env --allow-net server.ts

Check out a full implementation in the demo source code.

  1. When needed, you can delete all KV-stored OAuth 2.0 sessions and tokens.

    import { clearOAuthSessionsAndTokens } from "https://deno.land/x/deno_kv_oauth@$VERSION/mod.ts";
    
    await clearOAuthSessionsAndTokens();

Pre-configured OAuth 2.0 Clients

This module comes with a suite of pre-configured OAuth 2.0 clients for the following providers:

  1. Auth0
  2. Discord
  3. Dropbox
  4. Facebook
  5. GitHub
  6. GitLab
  7. Google
  8. Notion
  9. Okta
  10. Patreon
  11. Slack
  12. Spotify
  13. Twitter

Each function is typed so that their respective platform's requirements are met.

If there's a pre-configured OAuth 2.0 client for a provider you'd like added, please submit a pull request or create a new issue.

Custom OAuth 2.0 Client

If you require custom OAuth 2.0 configuration, you must define your client using new OAuth2Client() from the oauth2_client module. E.g.:

import { OAuth2Client } from "https://deno.land/x/oauth2_client/mod.ts";

const client = new OAuth2Client({
  clientId: Deno.env.get("CUSTOM_CLIENT_ID")!,
  clientSecret: Deno.env.get("CUSTOM_CLIENT_SECRET")!,
  authorizationEndpointUri: "https://custom.com/oauth/authorize",
  tokenUri: "https://custom.com/oauth/token",
  redirectUri: "https://my-site.com",
});

Environment Variables

  • KV_PATH (optional) - defines the path that Deno KV uses. See the API reference for further details.
  • ${PROVIDER}_CLIENT_ID and ${PROVIDER}_CLIENT_SECRET - required when creating a pre-configured OAuth 2.0 client for a given provider. E.g. for Twitter, the environment variable keys are TWITTER_CLIENT_ID and TWITTER_CLIENT_SECRET. See the list below for specifics.
  • OKTA_DOMAIN or AUTH0_DOMAIN - required only when using the Okta or Auth0 provider to supply your own given domain.

Note: reading environment variables requires the --allow-env[=<VARIABLE_NAME>...] permission flag. See the manual for further details.

Running the Demo

Run deno task demo to start the demo application. The task uses environment variables defined in a .env file at the root of this folder.

By default, the demo uses GitHub with a minimal scope. Use the PROVIDER and SCOPE environment variables, if you'd like to change this behavior. E.g. for Twitter:

PROVIDER=Twitter SCOPE=users.read deno task demo

Redirect URL after Sign-In or Sign-Out

The URL that the client is redirected to upon successful sign-in or sign-out is determined by the request made to the sign-in or sign-out endpoint. This value is set by the following order of precedence:

  1. The value of the success_url URL parameter of the request URL, if defined. E.g. a request to http://example.com/signin?success_url=/success redirects the client to /success after successful sign-in.
  2. The value of the Referer header, if of the same origin as the request. E.g. a request to http://example.com/signin with Referer header http://example.com/about redirects the client to http://example.com/about after successful sign-in.
  3. The root path, "/". E.g. a request to http://example.com/signin without the Referer header redirects the client to http://example.com after successful sign-in.

The same applies to user sign-out.

Known Issues

Twitch Incompatibility

This module is incompatible with Twitch as an OAuth 2.0 provider, as the platform doesn't support PKCE. PKCE is a requirement for all OAuth 2.0 providers for this module.

In the Wild

Check out these projects powered by Deno KV OAuth 2.0:

  1. Deno SaaSKit / Deno Hunt - A modern SaaS template built on Fresh.
  2. KV SketchBook - Dead simple sketchbook app.
  3. Fresh + Deno KV OAuth demo - A demo of Deno KV OAuth working in the Fresh web framework.
  4. Oak + Deno KV OAuth demo - A demo of Deno KV OAuth working in the Oak web framework.
  5. Ultra + Deno KV OAuth demo - A demo of Deno KV OAuth working in the Ultra web framework.
  6. Hono + Deno KV OAuth demo - A demo of Deno KV OAuth working in the Hono web framework.
  7. Cheetah + Deno KV OAuth demo - A demo of Deno KV OAuth working in the Cheetah web framework.
  8. Paquet - A web app shop

Do you have a project powered by Deno KV OAuth 2.0 that you'd like to share? Please submit a pull request adding that project to this list.