メインコンテンツまでスキップ
バージョン: 🚧 Canary

🔗 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},
),
);
ConfigurationDefault / source behaviorEffect
dataStores.identitiesRequired for every callbackFinds provider identities and creates one for oauth-signup.
dataStores.refreshtokensRequired for authServiceStores generated refresh tokens.
dataStores.onetimetokensRequired for every callbackStores the generated login one-time token.
configuration.authSecretsRequired for initiation and callbackSigns provider state and verifies it on Google/LINE callbacks; signs the final one-time token.
configuration.oauth.allowedRedirectOriginsOptional in the interface; no default allowlist; must be nonempty for initiation and callback redirect validationAllows frontend redirect origins for Google, LINE, and Twitter. Missing or empty values reject redirects.
configuration.onetimeTokenSignOptionsPassed to provider-state or final login-token generation; authService defaults to { expiresIn: '5m' }Controls one-time-token lifetime.
Provider driverRequired for its two routesSupplies 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​

TaskStart withContract
Start Google login or signupgoogleOAuthFeaturePublic googleOAuthFeature and googleOAuthRoute; query values follow googleOauthSchema
Start LINE login or signuplineOAuthFeaturePublic lineOAuthFeature and lineOAuthRoute; query values follow lineOauthSchema
Start Twitter login or signuptwitterOAuthFeaturePublic twitterOAuthFeature and twitterOAuthRoute; query values follow twitterOauthSchema
Handle a provider returnOAuth callback featuresValidates the state's redirectUrl against configuration.oauth.allowedRedirectOrigins, then redirects to the allowed URL with ?onetimeToken=<token>.
Validate a redirect originblocks.validateURLReturns 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​

PagePurpose
BlocksProvider-state, token, fingerprint, redirect helpers, and validateURL origin validation.
FeaturesSchema-to-route OAuth compositions.
RoutesPublic initiation and callback endpoint contracts.
SchemasProvider initiation query validation.

OAuth has no handlers.md or validators.md page; it composes through Authentication.

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.