🔐 OAuth Drivers
OAuth drivers provide a consistent integration layer for third-party OAuth providers using Passport.js. They encapsulate provider strategy setup and expose Promise-based request and callback helpers for composition into routes and features.
🎯 Overview
OAuth drivers in NodeBlocks are thin wrappers around Passport.js strategies for Google, Twitter, and LINE. Each factory is synchronous — no await is required.
import { drivers } from '@nodeblocks/backend-sdk';
const {
createGoogleOAuthDriver,
createTwitterOAuthDriver,
createLineOAuthDriver,
verifyGoogleCallback,
verifyTwitterCallback,
verifyLineCallback,
PROVIDER_GOOGLE,
PROVIDER_TWITTER,
PROVIDER_LINE,
TWITTER_CALLBACK_STATE_SESSION_KEY,
} = drivers;
Each factory returns a driver object with three methods:
| Method | Purpose |
|---|---|
initialize(app) | Register Passport and any required middleware on the Express app |
request(req, res, state) | Start the OAuth authorization flow |
callback(req, res) | Handle the OAuth callback and return the normalized profile |
Driver constants:
| Export | Value | Source file |
|---|---|---|
PROVIDER_GOOGLE | 'google' | src/drivers/oauth/google.ts |
PROVIDER_TWITTER | 'twitter' | src/drivers/oauth/twitter/index.ts |
PROVIDER_LINE | 'line' | src/drivers/oauth/line/index.ts |
TWITTER_CALLBACK_STATE_SESSION_KEY | 'twitter-callback-state' | src/drivers/oauth/twitter/index.ts |
Global side effect: Each factory calls
passport.use(new ...Strategy(...))on the shared Passport singleton. Calling multiple factory functions registers strategies on the same Passport instance for the process.
Types — driver interfaces and profile types live under the types namespace (SDK source: src/types/oauth.ts):
import { types } from '@nodeblocks/backend-sdk';
type GoogleOAuthDriver = types.GoogleOAuthDriver;
type GoogleProfile = types.GoogleProfile;
type TwitterOAuthDriver = types.TwitterOAuthDriver;
type TwitterProfile = types.TwitterProfile;
type TwitterCallbackState = types.TwitterCallbackState;
type TwitterRequest = types.TwitterRequest;
type LineOAuthDriver = types.LineOAuthDriver;
type LineProfile = types.LineProfile;
// OAUTH_LOGIN, OAUTH_SIGNUP, OAuthLoginState, ...
Callback URLs: Register the same redirect URI in your OAuth provider console and pass it to the driver factory. SDK OAuth routes use
/auth/oauth/{provider}/callback(for example/auth/oauth/google/callback). YourcallbackURLmust match both the provider registration and the route path mounted by Authentication Service.
📋 Available OAuth Drivers
Google OAuth Driver
Integrates the Passport.js Google OAuth 2.0 strategy (passport-google-oauth20).
createGoogleOAuthDriver
| Parameter | Type | Default | Description |
|---|---|---|---|
clientID | string | — | Google OAuth client ID |
clientSecret | string | — | Google OAuth client secret |
callbackURL | string | — | Redirect URL after OAuth completion |
scope | string[] | ['email', 'profile'] | OAuth scopes |
verify | typeof verifyGoogleCallback | verifyGoogleCallback | Optional verify function |
Returns: GoogleOAuthDriver
const googleDriver = createGoogleOAuthDriver(
process.env.GOOGLE_CLIENT_ID!,
process.env.GOOGLE_CLIENT_SECRET!,
'https://app.com/auth/oauth/google/callback'
);
googleDriver.initialize(app);
Google driver methods
The strategy uses passReqToCallback: true — custom verify functions receive req as the first argument (the default verifyGoogleCallback ignores it).
| Method | Signature | Returns |
|---|---|---|
initialize | (app: Express) => void | Registers passport.initialize() |
request | (req, res, state: string) => Promise<void> | Starts OAuth with { prompt: 'consent', state } |
callback | (req, res) => Promise<GoogleProfile> | { displayName, email, id } with session: false |
Twitter OAuth Driver
Custom OAuth 2.0 strategy with PKCE (not the legacy passport-twitter package).
createTwitterOAuthDriver
| Parameter | Type | Default | Description |
|---|---|---|---|
clientID | string | — | Twitter application App ID |
clientSecret | string | — | Twitter application App Secret |
callbackURL | string | — | Callback URL for Twitter OAuth |
sessionSecret | string | — | Secret for express-session |
verify | VerifyFunctionWithRequest | verifyTwitterCallback | Optional verify function |
Returns: TwitterOAuthDriver
Session middleware (registered in initialize on ['/auth/oauth/twitter', '/auth/oauth/twitter/callback']):
| Setting | Value |
|---|---|
resave | false |
saveUninitialized | false |
| Cookie | httpOnly, sameSite: 'lax', secure: 'auto', maxAge: 10 minutes |
Strategy defaults (built into TwitterStrategy — not configurable via the factory):
| Setting | Value |
|---|---|
| Scopes | ['users.read', 'tweet.read'] |
| PKCE | true |
| Authorization URL | https://twitter.com/i/oauth2/authorize |
| Token URL | https://api.twitter.com/2/oauth2/token |
| Profile URL | https://api.twitter.com/2/users/me |
const twitterDriver = createTwitterOAuthDriver(
process.env.TWITTER_CLIENT_ID!,
process.env.TWITTER_CLIENT_SECRET!,
'https://app.com/auth/oauth/twitter/callback',
process.env.SESSION_SECRET!
);
twitterDriver.initialize(app);
Twitter driver methods
| Method | Signature | Returns |
|---|---|---|
initialize | (app: Express) => void | Session middleware on Twitter routes, then passport.initialize() |
request | (req: TwitterRequest, res, state: TwitterCallbackState) => Promise<void> | Stores state in req.session[TWITTER_CALLBACK_STATE_SESSION_KEY], starts OAuth |
callback | (req: TwitterRequest, res) => Promise<{ state: TwitterCallbackState; user: TwitterProfile }> | Session state + user profile |
TwitterCallbackState shape: { typeId, redirectUrl, purpose } — purpose values align with types.OAUTH_LOGIN / types.OAUTH_SIGNUP.
Callback errors:
| Condition | Error |
|---|---|
| Passport returns no user | AuthenticationOAuthError with status/info from Passport |
| Session state missing | AuthenticationOAuthError: 'Twitter OAuth authentication failed. Session state required for executing callback not found.' |
On success, callback always returns { state, user } — state is required at runtime (the TypeScript return type marks it optional, but the implementation rejects when absent).
LINE OAuth Driver
Custom OAuth 2.0 strategy for LINE Login.
createLineOAuthDriver
| Parameter | Type | Default | Description |
|---|---|---|---|
clientID | string | — | LINE channel ID |
clientSecret | string | — | LINE channel secret |
callbackURL | string | — | Redirect URL after OAuth completion |
scope | string[] | ['profile', 'openid', 'email'] | OAuth scopes (overrides strategy default) |
verify | VerifyFunctionWithRequest | verifyLineCallback | Optional verify function |
Returns: LineOAuthDriver
Strategy defaults (built into LineStrategy):
| Setting | Value |
|---|---|
| Authorization URL | https://access.line.me/oauth2/v2.1/authorize |
| Token URL | https://api.line.me/oauth2/v2.1/token |
| Profile URL | https://api.line.me/oauth2/v2.1/userinfo |
| Built-in scope (before factory override) | ['openid'] |
The factory scope parameter overrides the built-in default.
const lineDriver = createLineOAuthDriver(
process.env.LINE_CHANNEL_ID!,
process.env.LINE_CHANNEL_SECRET!,
'https://app.com/auth/oauth/line/callback'
);
lineDriver.initialize(app);
LINE driver methods
| Method | Signature | Returns |
|---|---|---|
initialize | (app: Express) => void | Registers passport.initialize() |
request | (req, res, state: string) => Promise<void> | Starts OAuth with { session: false, state } |
callback | (req, res) => Promise<LineProfile> | { name, sub } with session: false |
Types vs implementation:
LineOAuthDriver.requestis typed asLineRequestAuthenticationinsrc/types/oauth.ts, which includes an optionalscopeparameter — the driver implementation accepts(req, res, state)only.
Callback errors: When Passport returns no user, callback rejects with AuthenticationOAuthError (including status/info from Passport). Verify failures also reject the returned Promise.
Custom verify functions
Each factory accepts an optional verify parameter (defaults shown in the factory tables above). Default verify functions are exported from the drivers namespace:
const { verifyGoogleCallback, verifyTwitterCallback, verifyLineCallback } = drivers;
verifyGoogleCallback
Validates profile.emails[0].value and profile.id, then passes { displayName, email, id } to Passport. displayName may be undefined at runtime if Google omits it; only email and id are validated. Missing required data produces AuthenticationBadRequestError with message 'Google oauth payload error'.
verifyTwitterCallback
Validates profile, profile.id, and profile.username, then passes { displayName: profile.name, id, username } to Passport. displayName may be undefined at runtime if Twitter omits name. Missing data produces AuthenticationOAuthError.
verifyLineCallback
Validates profile.sub, then passes { name: profile?.name, sub } to Passport. name may be undefined at runtime if LINE omits it. Custom verify functions receive LineUserInfoPayload from the internal strategy (src/drivers/oauth/line/strategy.ts); it is not exported from drivers. Missing sub produces AuthenticationOAuthError with message 'Cannot get sub from line oauth payload'.
Verify failures call Passport done(error) — the driver callback Promise rejects.
🔧 Using OAuth Drivers
With Services
Create drivers, call initialize(app) on each, then inject via the third-argument options on authService:
import { services, drivers } from '@nodeblocks/backend-sdk';
const { authService } = services;
const {
createGoogleOAuthDriver,
createTwitterOAuthDriver,
createLineOAuthDriver,
} = drivers;
const googleOAuthDriver = createGoogleOAuthDriver(
process.env.GOOGLE_CLIENT_ID!,
process.env.GOOGLE_CLIENT_SECRET!,
'https://app.com/auth/oauth/google/callback'
);
const twitterOAuthDriver = createTwitterOAuthDriver(
process.env.TWITTER_CLIENT_ID!,
process.env.TWITTER_CLIENT_SECRET!,
'https://app.com/auth/oauth/twitter/callback',
process.env.SESSION_SECRET!
);
const lineOAuthDriver = createLineOAuthDriver(
process.env.LINE_CHANNEL_ID!,
process.env.LINE_CHANNEL_SECRET!,
'https://app.com/auth/oauth/line/callback'
);
googleOAuthDriver.initialize(app);
twitterOAuthDriver.initialize(app);
lineOAuthDriver.initialize(app);
authService(
dataStores,
{
authSecrets: {
authEncSecret: process.env.AUTH_ENC_SECRET!,
authSignSecret: process.env.AUTH_SIGN_SECRET!,
},
},
{ googleOAuthDriver, twitterOAuthDriver, lineOAuthDriver }
);
See Authentication Service for full Express wiring, data stores, session/cookie setup, OAuth env vars, and other third-argument options (mailService, etc.).
🔗 Related Documentation
- Drivers Overview — Full drivers export inventory
- OAuth Blocks — Business logic for OAuth flows
- OAuth Routes — HTTP route compositions for OAuth
- Authentication Service — Service wiring for OAuth drivers