Skip to main content

OIDCInteractionBridge

Package: @nauth-toolkit/oidc-provider Type: Service

Drives the login and consent steps of a pending authorization request from your own routes.

import { OIDCInteractionBridge } from '@nauth-toolkit/oidc-provider';

Overview​

Call these from ordinary routes in your application, inside your guard chain, so the request context that identifies the current user is populated. Pass the framework request and response straight through — Express objects, Fastify request/reply, or NAuthRequest.raw / NAuthResponse.raw all work.

Every method answers with a redirectTo rather than issuing a 302, so a single-page app can drive the flow with fetch and navigate itself.

Every decision is also written to your audit trail as an OIDC_* event, with the relying party attached, unless auditLogs.enabled is false.

note

With NestJS, inject it with @Inject(NAUTH_OIDC_BRIDGE). The shipped controller already does.

Constructing it yourself​

Only needed outside NestJS, or when you register the bridge in your own module.

src/oidc.ts
import { OIDCInteractionBridge } from '@nauth-toolkit/oidc-provider';
import { IdpSessionGate } from '@nauth-toolkit/core/internal';

const bridge = new OIDCInteractionBridge(
provider,
new IdpSessionGate(dataSource.getRepository(User), authConfig),
);

A third argument accepts an AuthAuditService; omit it and no audit events are written.

Methods​

abort()​

Abandon a pending interaction, so the relying party gets a clean access_denied instead of waiting on a browser tab the user closed.

async abort(req: unknown, res: unknown): Promise<InteractionRedirectDTO>

Parameters

  • req - The framework request
  • res - The framework response

Returns

Errors

CodeWhenDetails
OIDC_INTERACTION_NOT_FOUNDExpired or already resolved{ cause: string }

Throws NAuthException with the code listed above.


completeConsent()​

Record the user's consent decision. On approval this saves a Grant — the durable record of what this user let this client see — and resolves the interaction with its id.

async completeConsent(
req: unknown,
res: unknown,
decision: { approve: boolean; scopes?: string[] },
): Promise<InteractionRedirectDTO>

Parameters

  • req - The framework request
  • res - The framework response
  • decision.approve - Whether the user approved
  • decision.scopes - A narrowed scope set. Omit to grant every missing scope

Returns

Errors

CodeWhenDetails
OIDC_INTERACTION_NOT_FOUNDExpired, or the grant is gone{ uid?: string, cause?: string }
OIDC_LOGIN_REQUIREDThe session lapsed while the consent screen was open{ uid: string, reason: string }

Throws NAuthException with the codes listed above.

A denied account does not throw — the interaction resolves with access_denied, so the returned redirectTo carries a protocol error back to the relying party. completeLogin() behaves the same way.


completeLogin()​

Complete the login step for the currently authenticated user.

async completeLogin(req: unknown, res: unknown): Promise<InteractionRedirectDTO>

The account is re-read from the database here, so a user disabled, locked, or newly required to change their password since their access token was issued cannot have an id_token minted for a third party.

Parameters

  • req - The framework request
  • res - The framework response

Returns

Errors

CodeWhenDetails
OIDC_INTERACTION_NOT_FOUNDExpired or already resolved{ cause: string }
OIDC_LOGIN_REQUIREDNo completed login behind the request{ uid: string, reason: string }

Throws NAuthException with the codes listed above.

details.reason is the session gate's verdict: 'no_session', 'password_change_required' or 'email_verification_required'.


getState()​

Describe a pending interaction so the frontend can decide what to render. Callable anonymously — the answer for a signed-out user is precisely what tells the frontend to send them to login.

async getState(req: unknown, res: unknown): Promise<InteractionStateDTO>

Parameters

  • req - The framework request
  • res - The framework response

Returns

Errors

CodeWhenDetails
OIDC_INTERACTION_NOT_FOUNDNo such pending request{ cause: string }

Throws NAuthException with the codes listed above.

What's Next​