Deno KV OAuth (Beta)
Features
- Uses oauth2_client for OAuth workflows and Deno KV for persistent session storage.
- Automatically handles the authorization code flow with Proof Key for Code Exchange (PKCE), access token refresh, and client redirection.
- Comes with pre-defined OAuth configurations for popular providers.
- Works locally and in the cloud, including Deno Deploy.
- Based on the
Request
andResponse
interfaces from the Web API. - Works with
std/http's
serve()
andDeno.serve()
native HTTP servers, and web frameworks such as Fresh and Oak. See the In the Wild section below for examples and demos.
Live Demo
You can also check out a live demo at https://kv-oauth.deno.dev, which uses Github as the OAuth provider. Source code is located in demo.ts.
Usage
Check out the full documentation and API reference here.
Fresh
Getting Started withNote: 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
andGET /oauth/signout
routes.
Create your OAuth 2.0 application for your given provider.
Create your pre-defined or custom OAuth configuration and configure Fresh to use the plugin.
// main.ts import { start } from "$fresh/server.ts"; import { createGithubOAuthConfig, kvOAuthPlugin, } from "https://deno.land/x/deno_kv_oauth@$VERSION/mod.ts"; import manifest from "./fresh.gen.ts"; await start(manifest, { plugins: [ kvOAuthPlugin(createGithubOAuthConfig()), ], });
If you require more advanced setups, you can create your own plugin. For more information, see:
- The source code for
kvOAuthPlugin()
- The Plugin documentation for Fresh
- The Fresh + Deno KV OAuth demo which uses the Fresh plugin
- Deno SaaSKit's custom plugin implementation
Getting Started with Other Frameworks
This example uses GitHub as the OAuth provider. However, you can use any provider you like.
Create your OAuth application for your given provider.
Create your pre-defined or custom OAuth configuration.
// Pre-configured OAuth client import { createGitHubOAuthConfig } from "https://deno.land/x/deno_kv_oauth@$VERSION/mod.ts"; const oauthConfig = createGitHubOAuthConfig();
Using the OAuth client configuration, insert the authentication flow functions into your authentication routes.
// Sign-in, callback and sign-out handlers import { createGitHubOAuthConfig, handleCallback, signIn, signOut, } from "https://deno.land/x/deno_kv_oauth@$VERSION/mod.ts"; const oauthConfig = createGitHubOAuthConfig(); async function handleSignIn(request: Request) { return await signIn(request, oauthConfig); } async function handleOAuth2Callback(request: Request) { return await handleCallback(request, oauthConfig); } async function handleSignOut(request: Request) { return await signOut(request); }
Use Deno KV OAuth's helper functions where needed.
// Protected route import { createGitHubOAuthConfig, getSessionAccessToken, getSessionId, } from "https://deno.land/x/deno_kv_oauth@$VERSION/mod.ts"; const oauthConfig = createGitHubOAuthConfig(); 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(oauthConfig, 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(); } }
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.
When needed, you can delete all KV-stored OAuth sessions and tokens.
import { clearOAuthSessionsAndTokens } from "https://deno.land/x/deno_kv_oauth@$VERSION/mod.ts"; await clearOAuthSessionsAndTokens();
Pre-Defined OAuth Configurations
This module comes with a suite of pre-defined OAuth configurations for the following providers:
Each function is typed so that their respective platform's requirements are met.
If there's a pre-configured OAuth client for a provider you'd like added, please submit a pull request or create a new issue.
Custom OAuth Configuration
Custom OAuth must be defined using
OAuth2ClientConfig
from the oauth2_client
module.
E.g.:
import type { OAuth2ClientConfig } from "https://deno.land/x/oauth2_client/mod.ts";
const oauthConfig: OAuth2ClientConfig = {
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 client for a given provider. E.g. for Twitter, the environment variable keys areTWITTER_CLIENT_ID
andTWITTER_CLIENT_SECRET
. See the list below for specifics.OKTA_DOMAIN
orAUTH0_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:
- The value of the
success_url
URL parameter of the request URL, if defined. E.g. a request tohttp://example.com/signin?success_url=/success
redirects the client to/success
after successful sign-in. - The value of the
Referer
header, if of the same origin as the request. E.g. a request tohttp://example.com/signin
withReferer
headerhttp://example.com/about
redirects the client tohttp://example.com/about
after successful sign-in. - The root path, "/". E.g. a request to
http://example.com/signin
without theReferer
header redirects the client tohttp://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 providers for this module.
In the Wild
Check out these projects powered by Deno KV OAuth:
- Deno SaaSKit - A modern SaaS template built on Fresh.
- KV SketchBook - Dead simple sketchbook app.
- Fresh + Deno KV OAuth demo - A demo of Deno KV OAuth working in the Fresh web framework.
- Oak + Deno KV OAuth demo - A demo of Deno KV OAuth working in the Oak web framework.
- Ultra + Deno KV OAuth demo - A demo of Deno KV OAuth working in the Ultra web framework.
- Hono + Deno KV OAuth demo - A demo of Deno KV OAuth working in the Hono web framework.
- Cheetah + Deno KV OAuth demo - A demo of Deno KV OAuth working in the Cheetah web framework.
- Paquet - A web app shop
Do you have a project powered by Deno KV OAuth that you'd like to share? Please submit a pull request adding that project to this list.