npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@hono/oauth-providers

v0.6.2

Published

Social login for Hono JS, integrate authentication with facebook, github, google and linkedin to your projects.

Downloads

2,022

Readme

OAuth Providers Middleware

Authentication middleware for Hono. This package offers a straightforward API for social login with platforms such as Facebook, GitHub, Google, LinkedIn and X(Twitter).

Installation

You can install hono and @hono/oauth-providers via npm.

npm i hono @hono/oauth-providers

Usage

Open Auth simplifies the OAuth2 flow, enabling you to utilize social login with just a single method. On every platform you choose to add to your project you have to add on its platform the callback uri or redirect uri. Open Auth handles the redirect uri internally as the route you are using the middleware on, so if you decide to use the google auth on the route /api/v1/auth/google/ the redirect uri will be DOMAIN/api/v1/auth/google.

app.use(
  "api/v1/auth/google", // -> redirect_uri by default
  googleAuth({ ... })
)

Also, there is two ways to use this middleware:

app.use(
  '/google',
  googleAuth({
    client_id: Bun.env.GOOGLE_ID,
    client_secret: Bun.env.GOOGLE_SECRET,
    scope: ['openid', 'email', 'profile'],
  })
)

app.get('/google', (c) => {
  const token = c.get('token')
  const grantedScopes = c.get('granted-scopes')
  const user = c.get('user-google')

  return c.json({
    token,
    grantedScopes,
    user,
  })
})

export default app

Or

app.get(
  '/google',
  googleAuth({
    client_id: Bun.env.GOOGLE_ID,
    client_secret: Bun.env.GOOGLE_SECRET,
    scope: ['openid', 'email', 'profile'],
  }),
  (c) => {
    const token = c.get('token')
    const grantedScopes = c.get('granted-scopes')
    const user = c.get('user-google')

    return c.json({
      token,
      grantedScopes,
      user,
    })
  }
)

export default app

Google

import { Hono } from 'hono'
import { googleAuth } from '@hono/oauth-providers/google'

const app = new Hono()

app.use(
  '/google',
  googleAuth({
    client_id: Bun.env.GOOGLE_ID,
    client_secret: Bun.env.GOOGLE_SECRET,
    scope: ['openid', 'email', 'profile'],
  })
)

export default app

Parameters

  • client_id:
    • Type: string.
    • Required.
    • Your app client ID. You can find this value in the API Console Credentials page. When developing Cloudflare Workers, there's no need to send this parameter. Just declare it in the wrangler.toml file as GOOGLE_ID=.
  • client_secret:
    • Type: string.
    • Required.
    • Your app client secret. You can find this value in the API Console Credentials page. When developing Cloudflare Workers, there's no need to send this parameter. Just declare it in the wrangler.toml file as GOOGLE_SECRET=.

      ⚠️ Do not share your client secret to ensure the security of your app.

  • scope:
    • Type: string[].
    • Required.
    • Set of permissions to request the user's authorization to access your app for retrieving user information and performing actions on their behalf. Review all the scopes Google offers for utilizing their API on the OAuth 2.0 Scopes page.

      If your app is not verified by Google, the accessible scopes for your app are significantly limited.

  • login_hint:
    • Type: string.
    • Optional.
    • Set the parameter value to an email address or sub identifier to provide a hint to the Google Authentication Server who is asking for authentication.
  • prompt:
    • Type: string.
    • Optional.
    • Define the prompt the user will receive when logging into their Google account. If not sent, the user will only be prompted the first time your project requests access. Choose one of the following options:
      • none: Do not display any authentication or consent screens. Must not be specified with other values.
      • consent: Prompt the user for consent.
      • select_account: Prompt the user to select an account.

Authentication Flow

After the completion of the Google OAuth flow, essential data has been prepared for use in the subsequent steps that your app needs to take.

googleAuth method provides 3 set key data:

  • token:
    • Access token to make requests to the google API for retrieving user information and performing actions on their behalf.
    • Type:
      {
        token: string
        expires_in: number
      }
  • granted-scopes:
    • If the include_granted_scopes parameter was set to true, you can find here the scopes for which the user has granted permissions.
    • Type: string[].
  • user-google:
    • User basic info retrieved from Google
    • Type:
      {
        id: string
        email: string
        verified_email: boolean
        name: string
        given_name: string
        family_name: string
        picture: string
        locale: string
      }

To access this data, utilize the c.get method within the callback of the upcoming HTTP request handler.

app.get('/google', (c) => {
  const token = c.get('token')
  const grantedScopes = c.get('granted-scopes')
  const user = c.get('user-google')

  return c.json({
    token,
    grantedScopes,
    user,
  })
})

Revoke Token

In certain use cases, you may need to programmatically revoke a user's access token. In such scenarios, you can utilize the revokeToken method, which accepts the token to be revoked as its unique parameter.

import { googleAuth, revokeToken } from '@hono/oauth-providers/google'

app.post('/remove-user', async (c, next) => {
  await revokeToken(USER_TOKEN)

  // ...
})

Facebook

import { Hono } from 'hono'
import { facebookAuth } from '@hono/oauth-providers/facebook'

const app = new Hono()

app.use(
  '/facebook',
  facebookAuth({
    client_id: Bun.env.FACEBOOK_ID,
    client_secret: Bun.env.FACEBOOK_SECRET,
    scope: ['email', 'public_profile'],
    fields: [
      'email',
      'id',
      'first_name',
      'last_name',
      'middle_name',
      'name',
      'picture',
      'short_name',
    ],
  })
)

export default app

Parameters

  • client_id:
    • Type: string.
    • Required.
    • Your app client ID. You can find this value in the App Dashboard Dashboard page. When developing Cloudflare Workers, there's no need to send this parameter. Just declare it in the wrangler.toml file as FACEBOOK_ID=.
  • client_secret:
    • Type: string.
    • Required.
    • Your app client secret. You can find this value in the App Dashboard Dashboard page. When developing Cloudflare Workers, there's no need to send this parameter. Just declare it in the wrangler.toml file as FACEBOOK_SECRET=.

      ⚠️ Do not share your client secret to ensure the security of your app.

  • scope:
    • Type: string[].
    • Required.
    • Set of permissions to request the user's authorization to access your app for retrieving user information and performing actions on their behalf. Review all the scopes Facebook offers for utilizing their API on the Permissions page.

      If your app is not verified by Facebook, the accessible scopes for your app are significantly limited.

  • fields:
    • Type: string[].
    • Fields you request from the Facebook API to be sent once the user has logged in. You can find a comprehensive reference for all the fields you can request on the Facebook User Reference page.

Authentication Flow

After the completion of the Facebook OAuth flow, essential data has been prepared for use in the subsequent steps that your app needs to take.

facebookAuth method provides 3 set key data:

  • token:
    • Access token to make requests to the Facebook API for retrieving user information and performing actions on their behalf. It has a duration of 60 days.
    • Type:
      {
        token: string
        expires_in: number
      }
  • granted-scopes:
    • If the include_granted_scopes parameter was set to true, you can find here the scopes for which the user has granted permissions.
    • Type: string[].
  • user-facebook:
    • User basic info retrieved from Facebook
    • Type:
      {
        id: string
        name: string
        email: string
        picture: {
          data: {
            height: number
            is_silhouette: boolean
            url: string
            width: number
          }
        }
        first_name: string
        last_name: string
        short_name: string
      }

To access this data, utilize the c.get method within the callback of the upcoming HTTP request handler.

app.get('/facebook', (c) => {
  const token = c.get('token')
  const grantedScopes = c.get('granted-scopes')
  const user = c.get('user-facebook')

  return c.json({
    token,
    grantedScopes,
    user,
  })
})

GitHub

GitHub provides two types of Apps to utilize its API: the GitHub App and the OAuth App. To understand the differences between these apps, you can read this article from GitHub, helping you determine the type of App you should select.

Parameters

  • client_id:
    • Type: string.
    • Required.
    • Github App and Oauth App.
    • Your app client ID. You can find this value in the GitHub App settings or the OAuth App settings based on your App type. When developing Cloudflare Workers, there's no need to send this parameter. Just declare it in the wrangler.toml file as GITHUB_ID=.
  • client_secret:
    • Type: string.
    • Required.
    • Github App and Oauth App.
    • Your app client secret. You can find this value in the GitHub App settings or the OAuth App settings based on your App type. When developing Cloudflare Workers, there's no need to send this parameter. Just declare it in the wrangler.toml file as GITHUB_SECRET=.

      ⚠️ Do not share your client secret to ensure the security of your app.

  • scope:
    • Type: string[].
    • Required.
    • Oauth App.
    • Set of permissions to request the user's authorization to access your app for retrieving user information and performing actions on their behalf. Review all the scopes Github offers for utilizing their API on the Permissions page. For GitHub Apps, you select the scopes during the App creation process or in the settings.
  • oauthApp:
    • Type: boolean.
    • Required.
    • Oauth App.
    • Set this value to true if your App is of the OAuth App type. Defaults to false.

Authentication Flow

After the completion of the Github Auth flow, essential data has been prepared for use in the subsequent steps that your app needs to take.

githubAuth method provides 4 set key data:

  • token:
    • Access token to make requests to the Github API for retrieving user information and performing actions on their behalf.
    • Type:
      {
        token: string
        expires_in: number // -> only available for Oauth Apps
      }
  • refresh-token:
    • You can refresh new tokens using this token, which has a longer lifespan. Only available for Oauth Apps.
    • Type:
      {
        token: string
        expires_in: number
      }
  • user-github:
    • User basic info retrieved from Github
    • Type:
      {
        login:  string
        id:  number
        node_id:  string
        avatar_url:  string
        gravatar_id:  string
        url:  string
        html_url:  string
        followers_url:  string
        following_url:  string
        gists_url:  string
        starred_url:  string
        subscriptions_url:  string
        organizations_url:  string
        repos_url:  string
        events_url:  string
        received_events_url:  string
        type:  string
        site_admin:  boolean
        name:  string
        company:  string
        blog:  string
        location:  string
        email:  string  |  null
        hireable:  boolean  |  null
        bio:  string
        twitter_username:  string
        public_repos:  number
        public_gists:  number
        followers:  number
        following:  number
        created_at:  string
        updated_at:  string
        private_gists:  number, // -> Github App
        total_private_repos:  number, // -> Github App
        owned_private_repos:  number, // -> Github App
        disk_usage:  number, // -> Github App
        collaborators:  number, // -> Github App
        two_factor_authentication:  boolean, // -> Github App
        plan: {
          name:  string,
          space:  number,
          collaborators:  number,
          private_repos:  number
        } // -> Github App
      }
  • granted-scopes:
    • If the include_granted_scopes parameter was set to true, you can find here the scopes for which the user has granted permissions.

Github App Example

import { Hono } from 'hono'
import { githubAuth } from '@hono/oauth-providers/github'

const app = new Hono()

app.use(
  '/github',
  githubAuth({
    client_id: Bun.env.GITHUB_ID,
    client_secret: Bun.env.GITHUB_SECRET,
  })
)

app.get('/github', (c) => {
  const token = c.get('token')
  const user = c.get('user-github')

  return c.json({
    token,
    user,
  })
})

export default app

OAuth App Example

import { Hono } from 'hono'
import { githubAuth } from '@hono/oauth-providers/github'

const app = new Hono()

app.use(
  '/github',
  githubAuth({
    client_id: Bun.env.GITHUB_ID,
    client_secret: Bun.env.GITHUB_SECRET,
    scope: ['public_repo', 'read:user', 'user', 'user:email', 'user:follow'],
    oauthApp: true,
  })
)

app.get('/github', (c) => {
  const token = c.get('token')
  const refreshToken = c.get('refresh-token')
  const user = c.get('user-github')

  return c.json({
    token,
    refreshToken,
    user,
  })
})

export default app

LinkedIn

LinkedIn provides two types of Authorization to utilize its API: the Member Authotization and the Application Authorization. To understand the differences between these authorization methods, you can read this article from LinkedIn, helping you determine the type of Authorization your app should use.

Parameters

  • client_id:
    • Type: string.
    • Required.
    • Member and Application authorization.
    • Your app client ID. You can find this value in the LinkedIn Developer Portal. When developing Cloudflare Workers, there's no need to send this parameter. Just declare it in the wrangler.toml file as LINKEDIN_ID=.
  • client_secret:
    • Type: string.
    • Required.
    • Member and Application authorization.
    • Your app client secret. You can find this value in the LinkedIn Developer Portal. When developing Cloudflare Workers, there's no need to send this parameter. Just declare it in the wrangler.toml file as LINKEDIN_SECRET=.

      ⚠️ Do not share your client secret to ensure the security of your app.

  • scope:
    • Type: string[].
    • Required.
    • Member Authorization.
    • Set of permissions to request the user's authorization to access your app for retrieving user information and performing actions on their behalf. Review all the scopes LinkedIn offers for utilizing their API on the Getting Access docs page.
  • appAuth: - Type: boolean. - Required. - Application Authorization. - Set this value to true if your App uses the App Authorization method. Defaults to false.

    To access the Application Authorization method you have to ask LinkedIn for It. Apparently you have to verify your app then ask for access.

Authentication Flow

After the completion of the LinkedIn Auth flow, essential data has been prepared for use in the subsequent steps that your app needs to take.

linkedinAuth method provides 4 set key data:

  • token:
    • Access token to make requests to the LinkedIn API for retrieving user information and performing actions on their behalf.
    • Type:
      {
        token: string
        expires_in: number
      }
  • refresh-token:
    • You can refresh new tokens using this token, which has a longer lifespan. Only available for Member Authorization.
    • Type:
      {
        token: string
        expires_in: number
      }
  • user-linkedin:
    • User basic info retrieved from LinkedIn.
    • Type:
      {
        sub:  string
        email_verified:  boolean
        name:  string
        locale: {
          country:  string
          language:  string
        },
        given_name:  string
        family_name:  string
        email:  string
        picture:  string
      }

      Only available for Member Authorization.

  • granted-scopes:
    • If the include_granted_scopes parameter was set to true, you can find here the scopes for which the user has granted permissions.

Member Authentication Example

import { Hono } from 'hono'
import { linkedinAuth } from '@hono/oauth-providers/linkedin'

const app = new Hono()

app.use(
  '/linkedin',
  linkedinAuth({
    client_id: Bun.env.LINKEDIN_ID,
    client_secret: Bun.env.LINKEDIN_SECRET,
    scope: ['email', 'openid', 'profile'],
  })
)

app.get('/linkedin', (c) => {
  const token = c.get('token')
  const user = c.get('user-linkedin')

  return c.json({
    token,
    user,
  })
})

export default app

Application Example

import { Hono } from 'hono'
import { linkedinAuth } from '@hono/oauth-providers/linkedin'

const app = new Hono()

app.use(
  '/linkedin',
  linkedinAuth({
    client_id: Bun.env.LINKEDIN_ID,
    client_secret: Bun.env.LINKEDIN_SECRET,
    appAuth: true,
  })
)

app.get('/linkedin', (c) => {
  const token = c.get('token')

  return c.json(token)
})

export default app

Revoke Token

In certain use cases, you may need to programmatically revoke a user's access token. In such scenarios, you can utilize the revokeToken method.

Parameters:

  • client_id:
    • string.
  • client_secret:
    • string.
  • refresh_token:
    • string.

Return Value:

  • token:
    • string.
import { linkedinAuth, refreshToken } from '@hono/oauth-providers/linkedin'

app.post('linkedin/refresh-token', async (c, next) => {
  const token = await refreshToken(LINKEDIN_ID, LINKEDIN_SECRET, USER_REFRESH_TOKEN)

  // ...
})

X (Twitter)

import { Hono } from 'hono'
import { xAuth } from '@hono/oauth-providers/x'

const app = new Hono()

app.use(
  '/x',
  xAuth({
    client_id: Bun.env.X_ID,
    client_secret: Bun.env.X_SECRET,
    scope: ['tweet.read', 'users.read', 'offline.access'],
    fields: ['profile_image_url', 'url'],
  })
)

export default app

Parameters

  • client_id:
    • Type: string.
    • Required.
    • Your app client ID. You can find this value in the Developer Portal. When developing Cloudflare Workers, there's no need to send this parameter. Just declare it in the wrangler.toml file as X_ID=.
  • client_secret:
    • Type: string.
    • Required.
    • Your app client secret. You can find this value in the Developer Portal. When developing Cloudflare Workers, there's no need to send this parameter. Just declare it in the wrangler.toml file as X_SECRET=.

      ⚠️ Do not share your client secret to ensure the security of your app.

  • scope:
    • Type: string[].
    • Required.
    • Set of permissions to request the user's authorization to access your app for retrieving user information and performing actions on their behalf. Review all the scopes X(Twitter) offers for utilizing their API on the Documentation. If not sent the default fields x set are id, name and username.
  • fields:
    • Type: string[].
    • Optional.
    • Set of fields of the user information that can be retreived from X. Check All the fields available on the get user me reference.

Authentication Flow

After the completion of the X OAuth flow, essential data has been prepared for use in the subsequent steps that your app needs to take.

xAuth method provides 4 set key data:

  • token:
    • Access token to make requests to the x API for retrieving user information and performing actions on their behalf.
    • Type:
      {
        token: string
        expires_in: number
      }
  • refresh-token:
    • You can refresh new tokens using this token. The duration of this token is not specified on the X docs.
    • Type:
      {
        token: string
        expires_in: number
      }
  • granted-scopes:
    • Scopes for which the user has granted permissions.
    • Type: string[].
  • user-x:
    • User basic info retrieved from X
    • Type:
      {
        created_at: string
      	description: string
      	entities: {
      		url: {
      			urls: {
      				start: number
      				end: number
      				url: string
      				expanded_url: string
      				display_url: string
      			}
      		}
      	}
      	id: string
      	location: string
      	most_recent_tweet_id: string
      	name: string
      	profile_image_url: string
      	protected: boolean
      	public_metrics: {
      		followers_count: number
      		following_count: number
      		tweet_count: number
      		listed_count: number
      		like_count: number
      	}
      	url: string
      	username: string
      	verified_type: string
      	verified: boolean
      }

If you want to receive the refresh token you must add the offline.access in the scopes parameter. To access this data, utilize the c.get method within the callback of the upcoming HTTP request handler.

app.get('/x', (c) => {
  const token = c.get('token')
  const refreshToken = c.get('refresh-token')
  const grantedScopes = c.get('granted-scopes')
  const user = c.get('user-x')

  return c.json({
    token,
		refreshToken
    grantedScopes,
    user,
  })
})

Refresh Token

Once the user token expires you can refresh their token wihtout the need to prompt the user again for access. In such scenario, you can utilize the refreshToken method, which accepts the client_id, client_secret and refresh_token as parameters.

The refresh_token can be used once. Once the token is refreshed X gives you a new refresh_token along with the new token.

import { xAuth, refreshToken } from '@hono/oauth-providers/x'

app.post('/x/refresh', async (c, next) => {
  await refreshToken(CLIENT_ID, CLIENT_SECRET, REFRESH_TOKEN)

  // ...
})

Revoke Token

In certain use cases, you may need to programmatically revoke a user's access token. In such scenarios, you can utilize the revokeToken method, the client_id, client_secret and the token to be revoked as parameters.

It returns a boolean to tell whether the token was revoked or not.

import { xAuth, revokeToken } from '@hono/oauth-providers/x'

app.post('/remove-user', async (c, next) => {
  await revokeToken(CLIENT_ID, CLIENT_SECRET, USER_TOKEN)

  // ...
})

Discord

import { Hono } from 'hono'
import { discordAuth } from '@hono/oauth-providers/discord'

const app = new Hono()

app.use(
  '/discord',
  discordAuth({
    client_id: Bun.env.DISCORD_ID,
    client_secret: Bun.env.DISCORD_SECRET,
    scope: ['identify', 'email'],
  })
)

export default app

Parameters

  • client_id:
    • Type: string.
    • Required.
    • Your app client ID. You can find this value in the Developer Portal. When developing Cloudflare Workers, there's no need to send this parameter. Just declare it in the wrangler.toml file as DISCORD_ID=.
  • client_secret:
    • Type: string.
    • Required.
    • Your app client secret. You can find this value in the Developer Portal. When developing Cloudflare Workers, there's no need to send this parameter. Just declare it in the wrangler.toml file as DISCORD_SECRET=.

      ⚠️ Do not share your client secret to ensure the security of your app.

  • scope:
    • Type: string[].
    • Required.
    • Set of permissions to request the user's authorization to access your app for retrieving user information and performing actions on their behalf. Review all the scopes Discord offers for utilizing their API on the Documentation.

Authentication Flow

After the completion of the Discord OAuth flow, essential data has been prepared for use in the subsequent steps that your app needs to take.

discordAuth method provides 4 set key data:

  • token:
    • Access token to make requests to the Discord API for retrieving user information and performing actions on their behalf.
    • Type:
      {
        token: string
        expires_in: number
      }
  • refresh-token:
    • You can refresh new tokens using this token. The duration of this token is not specified on the Discord docs.
    • Type:
      {
        token: string
        expires_in: number
      }
      > [!NOTE]
      > The refresh token Discord retrieves no implicit expiration
  • granted-scopes:
    • Scopes for which the user has granted permissions.
    • Type: string[].
  • user-discord:
    • User basic info retrieved from Discord
    • Type:
      {
      	id: string
      	username: string
      	avatar: string
      	discriminator: string
      	public_flags: number
      	premium_type: number
      	flags: number
      	banner: string | null
      	accent_color: string | null
      	global_name: string
      	avatar_decoration_data: string | null
      	banner_color: string | null
      }

[!NOTE] To access this data, utilize the c.get method within the callback of the upcoming HTTP request handler.

app.get('/discord', (c) => {
  const token = c.get('token')
  const refreshToken = c.get('refresh-token')
  const grantedScopes = c.get('granted-scopes')
  const user = c.get('user-discord')

  return c.json({
    token,
		refreshToken
    grantedScopes,
    user,
  })
})

Refresh Token

Once the user token expires you can refresh their token wihtout the need to prompt the user again for access. In such scenario, you can utilize the refreshToken method, which accepts the client_id, client_secret and refresh_token as parameters.

[!NOTE] The refresh_token can be used once. Once the token is refreshed Discord gives you a new refresh_token along with the new token.

import { discordAuth, refreshToken } from '@hono/oauth-providers/discord'

app.post('/discord/refresh', async (c, next) => {
  const newTokens = await refreshToken(CLIENT_ID, CLIENT_SECRET, REFRESH_TOKEN)

  // newTokenes = {
  //   token_type: 'bear',
  //   access_token: 'skbjbfhj3b4348wdvbwje239'
  //   expires_in: 60000
  //   refresh_token: 'sfcb0dwd0hdeh29db'
  //   scope: "identify email"
  // }
  // ...
})

Revoke Token

In certain use cases, you may need to programmatically revoke a user's access token. In such scenarios, you can utilize the revokeToken method, the client_id, client_secret and the token to be revoked as parameters.

It returns a boolean to tell whether the token was revoked or not.

import { discordAuth, revokeToken } from '@hono/oauth-providers/discord'

app.post('/remove-user', async (c, next) => {
  const revoked = await revokeToken(CLIENT_ID, CLIENT_SECRET, USER_TOKEN)

  // revoked = true | false
  // ...
})

Advance Usage

Customize redirect_uri

All the provider middlewares also accept a redirect_uri parameter that overrides the default redirect_uri = c.req.url behavior.

This parameters can be useful if

  1. hono process cannot infer correct redirect_uri from the request. For example, when the server runs behind a reverse proxy and have no access to its internet hostname.
  2. Or, in need to start oauth flow from a different route.
  3. Or, in need to encode more info into redirect_uri.
const app = new Hono();

const SITE_ORIGIN = `https://my-site.com`;
const OAUTH_CALLBACK_PATH = `/oauth/google`;

app.get('/*',
  async (c, next) => {
    const session = readSession(c);
    if (!session) {
      // start oauth flow
      const redirectUri = `${SITE_ORIGIN}${OAUTH_CALLBACK_PATH}?redirect=${encodeURIComponent(c.req.path)}`;
      const oauth = googleAuth({ redirect_uri: redirectUri, ...more });
      return await oauth(c, next)
    }
  },
  async (c, next) => {
    // if we are here, the req should contain either a valid session or a valid auth code
    const session = readSession(c);
    const authedGoogleUser = c.get('user-google')
    if (authedGoogleUser) {
      await saveSession(c, authedGoogleUser);
    } else if (!session) {
      throw new HttpException(401)
    }
    return next();
  },
  async (c, next) => {
    // serve protected content
  }
);

Author

monoald https://github.com/monoald

License

MIT

Contribute

If you want to add new providers, features or solve some bugs don't doubt to create an issue or make a PR.

For testing purposes run the following code in the parent folder (middleware/):