🔗 OAuth
OAuth provides public browser initiation and callback routes for Google, LINE, and Twitter; it is composed by authService, not a standalone OAuth service.
Start here
Create each provider driver, register its middleware on the Express app, then mount authService. The callback URLs registered with a provider must include the same mount prefix as the SDK route: /auth/oauth/google/callback, /auth/oauth/line/callback, or /auth/oauth/twitter/callback. Use the root mount below when enabling Twitter: its driver installs session middleware only for the unprefixed Twitter SDK paths.
import express from 'express';
import {drivers, services} from '@nodeblocks/backend-sdk';
const app = express();
const googleOAuthDriver = drivers.createGoogleOAuthDriver(
'google-client-id',
'google-client-secret',
'https://app.example.test/auth/oauth/google/callback',
);
const twitterOAuthDriver = drivers.createTwitterOAuthDriver(
'twitter-client-id',
'twitter-client-secret',
'https://app.example.test/auth/oauth/twitter/callback',
'replace-with-a-session-secret',
);
const lineOAuthDriver = drivers.createLineOAuthDriver(
'line-client-id',
'line-client-secret',
'https://app.example.test/auth/oauth/line/callback',
);
twitterOAuthDriver.initialize(app);
googleOAuthDriver.initialize(app);
lineOAuthDriver.initialize(app);
app.use(
'/',
services.authService(
{identities, refreshtokens, onetimetokens},
{
authSecrets: {authEncSecret: 'replace-me', authSignSecret: 'replace-me'},
oauth: {allowedRedirectOrigins: ['https://client.example.test', 'http://localhost:3000']},
},
{googleOAuthDriver, twitterOAuthDriver, lineOAuthDriver},
),
);
| Configuration | Default / source behavior | Effect |
|---|---|---|
dataStores.identities | Required for every callback | Finds provider identities and creates one for oauth-signup. |
dataStores.refreshtokens | Required for authService | Stores generated refresh tokens. |
dataStores.onetimetokens | Required for every callback | Stores the generated login one-time token. |
configuration.authSecrets | Required for initiation and callback | Signs provider state and verifies it on Google/LINE callbacks; signs the final one-time token. |
configuration.oauth.allowedRedirectOrigins | Optional in the interface; no default allowlist; must be nonempty for initiation and callback redirect validation | Allows frontend redirect origins for Google, LINE, and Twitter. Missing or empty values reject redirects. |
configuration.onetimeTokenSignOptions | Passed to provider-state or final login-token generation; authService defaults to { expiresIn: '5m' } | Controls one-time-token lifetime. |
| Provider driver | Required for its two routes | Supplies request and callback; call its initialize(app) before requests. |
Google and LINE initiation state includes fp, purpose, redirectUrl, optional typeId, and user agent. Twitter passes { purpose, redirectUrl, typeId } to its driver, which maintains provider callback state. The SDK does not validate callback queries with a schema even though stateQueryParameter is exported.
Set oauth.allowedRedirectOrigins in the second authService argument to the origins of frontend destinations, such as https://client.example.test for https://client.example.test/oauth/complete. Provider driver callback URLs point to the backend and are configured separately. Use explicit origins without paths or wildcards; see the configuration reference and validateURL for matching rules.
Initiation and callback routes both validate the redirect origin. Missing/empty origins produce AuthenticationUnexpectedError, mapped to 500 by both initiation and callback routes. See route contracts.
Common tasks
| Task | Start with | Contract |
|---|---|---|
| Start Google login or signup | googleOAuthFeature | Public googleOAuthFeature and googleOAuthRoute; query values follow googleOauthSchema |
| Start LINE login or signup | lineOAuthFeature | Public lineOAuthFeature and lineOAuthRoute; query values follow lineOauthSchema |
| Start Twitter login or signup | twitterOAuthFeature | Public twitterOAuthFeature and twitterOAuthRoute; query values follow twitterOauthSchema |
| Handle a provider return | OAuth callback features | Validates the state's redirectUrl against configuration.oauth.allowedRedirectOrigins, then redirects to the allowed URL with ?onetimeToken=<token>. |
| Validate a redirect origin | blocks.validateURL | Returns ok(true) when the absolute URL's origin is allowed; returns an error for missing origins, malformed URLs, or disallowed origins. |
Browser workflow
Navigate to GET /auth/oauth/google?fp=device-fingerprint&purpose=oauth-login&redirectUrl=https%3A%2F%2Fclient.example.test%2Foauth%2Fcomplete. The initiation handler first validates the redirect URL against configuration.oauth.allowedRedirectOrigins. Malformed/disallowed destinations return 400 before the driver is called. For an allowed destination, the Google driver redirects the browser to Google. For oauth-signup, provide typeId; it is optional at schema level but identity creation rejects an absent value with 400.
Pass the absolute destination to a query serializer and let it encode the query parameter once:
const params = new URLSearchParams({
fp: 'device-fingerprint',
purpose: 'oauth-login',
redirectUrl: 'https://client.example.test/oauth/complete',
});
const loginUrl = `/auth/oauth/google?${params.toString()}`;
Do not call encodeURIComponent on the destination before passing it to URLSearchParams. That double-encodes the value: after request query parsing it still contains an encoded whole URL, which fails absolute-URL validation. SDK 0.15.0 also preserves percent encoding when constructing the final token redirect.
After provider authentication, Google and LINE receive state; Twitter receives driver-managed callback state. After obtaining provider state, the callback checks the state's redirectUrl with validateURL against configuration.oauth.allowedRedirectOrigins. The URL must be absolute and its origin must be allowed. Malformed/disallowed URLs return 400; missing/empty origins return 500. Validation failures stop before SDK identity checks, identity lookup/creation, token generation/storage, and the final redirect. Google validates before the signup email uniqueness check; LINE validates after state extraction, and Twitter validates after its driver returns state and profile.
After validation succeeds, the callback resolves or creates the identity, generates and stores a one-time token, and issues a 302 redirect using the state's redirectUrl with onetimeToken appended. generateRedirectURL preserves the supplied URL string and its percent encoding, such as %20 in a path; it performs no additional URL decoding. The redirect helper always appends ?onetimeToken=, so callers must provide a redirect URL whose query-string behavior they accept.
Custom feature composition
The service is the normal integration point. A custom host must pass the same stores, configuration, and provider driver in its composition context; a feature is an SDK composer, not Express middleware.
The configuration below must include authSecrets and a nonempty oauth.allowedRedirectOrigins allowlist for initiation and callback redirect validation, just as in the service setup above.
import {partial} from 'ramda';
import {features, primitives} from '@nodeblocks/backend-sdk';
const router = primitives.defService(
partial(primitives.compose(features.googleOAuthFeature, features.googleOAuthCallbackFeature), [
{configuration, dataStores: {identities, onetimetokens}, googleOAuthDriver},
]),
);
app.use('/', router);
Reference map
| Page | Purpose |
|---|---|
| Blocks | Provider-state, token, fingerprint, redirect helpers, and validateURL origin validation. |
| Features | Schema-to-route OAuth compositions. |
| Routes | Public initiation and callback endpoint contracts. |
| Schemas | Provider initiation query validation. |
OAuth has no handlers.md or validators.md page; it composes through Authentication.
Related modules
Authentication provides the containing service and one-time-token login. Authentication service defines configuration and mounting. OAuth drivers define Google, Twitter, and LINE driver factories and middleware. Authentication blocks provide token, fingerprint, and identity helpers; common blocks provide the final redirect.