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 🙏

© 2026 – Pkg Stats / Ryan Hefner

@strivacity/sdk-core

v3.0.2

Published

Strivacity JavaScript SDK client

Readme

@strivacity/sdk-core

A framework-agnostic JavaScript/TypeScript client that integrates Strivacity's policy-driven authentication journeys into any application using the OAuth 2.0 PKCE flow. Supports redirect, popup, native, and embedded modes.

See our Developer Portal to get started with developing with the Strivacity product.

Overview

This SDK provides the core authentication primitives for Strivacity's policy-driven journeys. It is a standalone JavaScript/TypeScript library with no framework dependencies that can be used directly or as the foundation for framework-specific SDKs (React, Vue, Angular, etc.). The SDK uses the OAuth 2.0 PKCE flow to authenticate with Strivacity.

Demo Application

Install

npm install @strivacity/sdk-core

Usage

Initialization

Create a flow instance using the initFlow factory function:

import { initFlow } from '@strivacity/sdk-core';

const sdk = initFlow({
	mode: 'redirect', // or 'popup', 'native', 'embedded'
	issuer: 'https://<YOUR_DOMAIN>',
	scopes: ['openid', 'profile'],
	clientId: '<YOUR_CLIENT_ID>',
	redirectUri: '<YOUR_REDIRECT_URI>',
});

Redirect / Popup mode

In redirect mode the user is taken to the identity provider in the same window; in popup mode authentication happens in a popup. Both are initiated the same way from code.

Login

await sdk.login();

Callback handling

Process the authorization callback after the identity provider redirects back to your application:

await sdk.handleCallback();

Logout

The postLogoutRedirectUri parameter is optional and specifies where users are redirected after logout. This URI must be configured in the Admin Console as an allowed post-logout redirect URI.

await sdk.logout({ postLogoutRedirectUri: location.origin });

Token refresh

Refreshes the access token using the stored refresh token, keeping the session alive without requiring the user to log in again.

await sdk.refresh();

Token revocation

Revokes the current access and refresh tokens on the server, invalidating the session immediately.

await sdk.revoke();

Native mode

In native mode, login() returns a NativeFlowHandler instance that drives the authentication UI step by step.

Login page example

The login page extracts session_id and optionally language from the URL on load and passes them to startSession() to resume an existing flow or start a new one. When a language parameter is present it overrides uiLocales to display the authentication UI in the specified language:

import { initFlow } from '@strivacity/sdk-core';

const sdk = initFlow({
	mode: 'native',
	issuer: 'https://<YOUR_DOMAIN>',
	scopes: ['openid', 'profile'],
	clientId: '<YOUR_CLIENT_ID>',
	redirectUri: '<YOUR_REDIRECT_URI>',
});

// Returns a NativeFlowHandler instance
const handler = await sdk.login();

// Extract session_id from URL if present
const url = new URL(window.location.href);
const sessionId = url.searchParams.get('session_id');

// Start a new session or resume an existing one
const state = await handler.startSession(sessionId);

if (state.finalizeUrl) {
	// Finalize the session when the flow is complete
	await handler.finalizeSession(state.finalizeUrl);
} else {
	// Render the form from state.widgets and handle user input
	console.log('Current form state:', state);
}

Submitting a form

const formState = await handler.submitForm('formId', {
	email: '[email protected]',
	password: 'secret',
});

if (formState.finalizeUrl) {
	await handler.finalizeSession(formState.finalizeUrl);
}

Callback page example

When a session_id is present in the URL the native flow is resumed by forwarding it to the login page. Otherwise the standard handleCallback() path is used:

const url = new URL(location.href);
const sessionId = url.searchParams.get('session_id');

if (sessionId) {
	// Forward to login page with session_id to resume the native flow
	window.location.href = `/login?session_id=${sessionId}`;
} else {
	try {
		await sdk.handleCallback();
		window.location.href = '/profile';
	} catch (error) {
		console.error('Error during callback handling:', error);
	}
}

Entry page example

The entry page processes flows started by an external process (e.g. password reset) by calling entry() to extract the necessary parameters to resume the flow:

try {
	const data = await sdk.entry();

	if (data && Object.keys(data).length > 0) {
		window.location.href = `/callback?${new URLSearchParams(data).toString()}`;
	} else {
		window.location.href = '/';
	}
} catch (error) {
	console.error('Entry failed:', error);
	window.location.href = '/';
}

Custom mode

Custom mode lets you replace the built-in flow implementations with your own classes. This is useful when you need to proxy authentication through a backend server (BFF pattern) rather than communicating with the identity provider directly from the browser.

Pass mode: 'custom' together with a customFlow class that extends one of the built-in flow base classes (NativeFlow, EmbeddedFlow, etc.):

import { initFlow } from '@strivacity/sdk-core';
import { CustomNativeFlow } from './sdk/CustomNativeFlow';

const sdk = initFlow({
	mode: 'custom',
	issuer: 'https://<YOUR_DOMAIN>',
	scopes: ['openid', 'profile'],
	clientId: '<YOUR_CLIENT_ID>',
	redirectUri: '<YOUR_REDIRECT_URI>',
	customFlow: CustomNativeFlow,
});

Creating a custom flow class

Extend NativeFlow (or EmbeddedFlow) and override the methods you need to change. The example below delegates session management to a backend API instead of calling the identity provider directly:

import type { NativeParams } from '@strivacity/sdk-core';
import { NativeFlow } from '@strivacity/sdk-core/flows/NativeFlow';
import { Session } from '@strivacity/sdk-core/utils/Session';
import { CustomNativeFlowHandler } from './CustomNativeFlowHandler';

export class CustomNativeFlow extends NativeFlow {
	override login(params: NativeParams = {}): CustomNativeFlowHandler {
		this.dispatchEvent('loginInitiated', []);
		return new CustomNativeFlowHandler(this, params);
	}

	override register(params: NativeParams = {}): CustomNativeFlowHandler {
		params.prompt = 'create';
		return this.login(params);
	}

	async fetchSessionData(): Promise<void> {
		const response = await this.httpClient.request(new URL('/api/session/info', location.origin).toString(), { method: 'GET', credentials: 'include' });

		this.session = Object.assign(new Session(), await response.json());

		if (!this.accessTokenExpired) {
			this.dispatchEvent('loggedIn', [{ claims: this.idTokenClaims! }]);
		}
	}

	override async refresh(): Promise<void> {
		const response = await this.httpClient.request(new URL('/api/session/refresh', location.origin).toString(), { method: 'POST', credentials: 'include' });

		if (!response.ok) {
			this.session = null;
			this.dispatchEvent('tokenRefreshFailed', [{}]);
			return;
		}

		this.session = Object.assign(new Session(), await response.json());
		this.dispatchEvent('tokenRefreshed', [{ claims: this.idTokenClaims! }]);
	}

	override async logout(): Promise<void> {
		this.dispatchEvent('logoutInitiated', []);

		await this.httpClient.request(new URL('/api/session/logout', location.origin).toString(), { method: 'POST', credentials: 'include' });

		this.session = null;
	}
}

Creating a custom flow handler

Extend NativeFlowHandler and override startSession and finalizeSession to communicate with your backend:

import type { LoginFlowState } from '@strivacity/sdk-core';
import { NativeFlowHandler } from '@strivacity/sdk-core/handlers/NativeFlowHandler';
import { CustomNativeFlow } from './CustomNativeFlow';

export class CustomNativeFlowHandler extends NativeFlowHandler {
	declare sdk: CustomNativeFlow;

	override async startSession(sessionId?: string | null, language?: string | null): Promise<LoginFlowState | void> {
		if (sessionId) {
			this.sessionId = sessionId;
			return this.submitForm();
		}

		if (language) {
			this.language = language;
		}

		const response = await this.sdk.httpClient.request(new URL('/api/session/start', location.origin).toString(), {
			method: 'POST',
			credentials: 'include',
			headers: { 'Content-Type': 'application/json' },
			body: JSON.stringify(this.params),
		});

		const data = await response.json();
		this.sessionId = data.session_id;

		return this.submitForm();
	}

	override async finalizeSession(finalizeUrl: string): Promise<void> {
		const finalizeResponse = await this.sdk.httpClient.request(finalizeUrl, {
			method: 'GET',
			headers: { Authorization: `Bearer ${this.sessionId}` },
			credentials: 'include',
		});

		const redirectUri = new URL(await finalizeResponse.text());

		await this.sdk.httpClient.request(new URL('/api/session/finalize', location.origin).toString(), {
			method: 'POST',
			headers: {
				'Content-Type': 'application/json',
				Authorization: `Bearer ${this.sessionId}`,
			},
			body: JSON.stringify(Object.fromEntries(redirectUri.searchParams)),
			credentials: 'include',
		});

		await this.sdk.fetchSessionData();
	}
}

Event subscription

The SDK provides an event system for listening to authentication lifecycle events:

const { dispose } = sdk.subscribeToEvent('loggedIn', (eventData) => {
	console.log('User logged in:', eventData);
});

// Later: unsubscribe
dispose();

Available events:

  • init: Fired when the SDK is initialized.
  • loggedIn: Fired when a user successfully logs in.
  • loginInitiated: Fired when a login flow is initiated.
  • sessionLoaded: Fired when an existing session is loaded.
  • accessTokenExpired: Fired when the access token expires.
  • tokenRefreshed: Fired when access tokens are successfully refreshed.
  • tokenRefreshFailed: Fired when token refresh fails.
  • logoutInitiated: Fired when logout is initiated.
  • tokenRevoked: Fired when tokens are successfully revoked.
  • tokenRevokeFailed: Fired when token revocation fails.

Logging

The SDK supports optional logging to help you debug authentication flows and monitor SDK behavior. You can enable the built-in console logger or provide your own custom logger implementation.

Using the Default Logger

Enable the default console logger by adding the logging option when calling initFlow:

import { initFlow, DefaultLogging } from '@strivacity/sdk-core';

const sdk = initFlow({
	mode: 'redirect',
	issuer: 'https://<YOUR_DOMAIN>',
	scopes: ['openid', 'profile'],
	clientId: '<YOUR_CLIENT_ID>',
	redirectUri: '<YOUR_REDIRECT_URI>',
	logging: DefaultLogging,
});

The default logger writes to the browser console and automatically prefixes messages with a correlation ID when available (via the xEventId property).

Creating a Custom Logger

Implement the SDKLogging interface and pass your class to the logging option:

import type { SDKLogging } from '@strivacity/sdk-core';

export class MyLogger implements SDKLogging {
	xEventId?: string;

	debug(message: string): void {
		console.debug(this.xEventId ? `[${this.xEventId}] ${message}` : message);
	}

	info(message: string): void {
		console.info(this.xEventId ? `[${this.xEventId}] ${message}` : message);
	}

	warn(message: string): void {
		console.warn(this.xEventId ? `[${this.xEventId}] ${message}` : message);
	}

	error(message: string, error: Error): void {
		console.error(this.xEventId ? `[${this.xEventId}] ${message}` : message, error);
	}
}
import { initFlow } from '@strivacity/sdk-core';
import { MyLogger } from './logging/MyLogger';

const sdk = initFlow({
	// ...other options
	logging: MyLogger,
});

The SDKLogging interface requires debug, info, warn, and error methods. The optional xEventId property, when set by the SDK, provides a correlation ID to trace related log messages across the authentication flow.

HTTP Client

The SDK uses a built-in fetch-based HTTP client for all requests. You can replace it with your own implementation by extending SDKHttpClient and passing your class via the httpClient option. This is useful when you need to attach custom headers (e.g. x-sty-app-id) to every outgoing request, route traffic through a proxy, or use a platform-specific transport such as Capacitor's CapacitorHttp.

Adding custom headers to every request

import { initFlow, SDKHttpClient, type HttpClientResponse } from '@strivacity/sdk-core';

class CustomHttpClient extends SDKHttpClient {
	async request<T>(url: string, options?: RequestInit): Promise<HttpClientResponse<T>> {
		const mergedOptions: RequestInit = {
			...options,
			headers: {
				'x-sty-app-id': 'my-app',
				...(options?.headers as Record<string, string>),
			},
		};

		const response = await fetch(url, mergedOptions);

		return {
			headers: response.headers,
			ok: response.ok,
			status: response.status,
			statusText: response.statusText,
			url: response.url,
			json: async () => (await response.json()) as T,
			text: async () => await response.text(),
		};
	}
}

const sdk = initFlow({
	// ...other options
	httpClient: CustomHttpClient,
});

Any header you add inside request() is automatically included in every SDK request

CORS configuration

For custom request headers to reach the Strivacity cluster, the cluster must be configured to explicitly allow them. Add the header name(s) to the Access-Control-Allow-Headers list in the cluster settings. Without this, browsers will block the preflight OPTIONS request and the SDK call will fail with a CORS error.

Access-Control-Allow-Headers: x-sty-app-id, <any other custom headers>

API Documentation

initFlow(options)

initFlow(options: SDKOptions): PopupFlow | RedirectFlow | NativeFlow | EmbeddedFlow

The initFlow function creates and returns a flow instance based on the mode specified in options.

Parameters:

| Name | Type | Required | Description | | ------------------ | ------------------------------------------------------------- | -------- | ------------------------------------------------------------------------------ | | issuer | string | ✅ | The issuer URL of the OpenID Provider. | | clientId | string | ✅ | The client identifier for the application. | | redirectUri | string | ✅ | The URI to redirect to after authentication. | | mode | 'redirect' \| 'popup' \| 'native' \| 'embedded' \| 'custom' | ⬜ | The authentication flow mode. Defaults to 'redirect'. | | scopes | string[] | ⬜ | The scopes to request. Defaults to ['openid']. | | responseType | 'code' \| 'id_token' | ⬜ | The response type. | | responseMode | 'query' \| 'fragment' | ⬜ | The response mode. | | storageTokenName | string | ⬜ | Custom name for the session storage key. Defaults to 'sty.session'. | | storage | SDKStorageType | ⬜ | Custom storage implementation. Defaults to LocalStorage. | | httpClient | SDKHttpClientType | ⬜ | Custom HTTP client implementation. | | logging | SDKLoggingType | ⬜ | Logging implementation class. | | customFlow | FlowType | ⬜ | Custom flow class. Required when mode is 'custom'. Must extend BaseFlow. |

Returns: A flow instance (PopupFlow, RedirectFlow, NativeFlow, EmbeddedFlow, or your custom flow class) depending on the configured mode.


Flow instance methods

All flow instances share the following methods:

  • login(options?: LoginOptions): Promise<void | NativeFlowHandler>: Initiates login. In native mode returns a NativeFlowHandler.
  • register(options?: RegisterOptions): Promise<void | NativeFlowHandler>: Initiates registration.
  • entry(url?: string): Promise<Record<string, string>>: Processes an externally-initiated flow URL and returns parameters needed to resume the flow.
  • handleCallback(url?: string): Promise<void>: Processes the authorization callback.
  • refresh(): Promise<void>: Refreshes the session tokens.
  • revoke(): Promise<void>: Revokes the current session tokens.
  • logout(options?: LogoutOptions): Promise<void>: Logs the user out.
  • subscribeToEvent(eventType: string, callback: Function): { dispose(): void }: Subscribes to an authentication lifecycle event. Returns an object with a dispose() method to unsubscribe.

Session state getters:

  • isAuthenticated: Promise<boolean>: Resolves to true when a valid session exists.
  • isAuthenticatedSync: boolean: Synchronous check for an active session.
  • idTokenClaims: IdTokenClaims | null: Claims from the ID token.
  • accessToken: string | null: The current access token.
  • refreshToken: string | null: The current refresh token.
  • accessTokenExpired: boolean: true when the access token has expired.
  • accessTokenExpirationDate: number | null: Expiration timestamp (Unix seconds) of the access token.

NativeFlowHandler

Returned by NativeFlow.login() and NativeFlow.register() to drive the step-by-step native authentication UI.

  • startSession(sessionId?: string | null): Promise<LoginFlowState | void>: Starts a new authentication session or resumes an existing one when sessionId is provided.
  • submitForm(formId?: string, body?: Record<string, unknown>): Promise<LoginFlowState>: Submits a form step in the authentication flow.
  • finalizeSession(finalizeUrl: string): Promise<void>: Finalizes the session using the URL returned in LoginFlowState.finalizeUrl.

subscribeToEvent(eventType, callback)

Subscribe to SDK lifecycle events.

Parameters:

| Name | Type | Required | Description | | ----------- | -------------------------- | -------- | ---------------------------------------- | | eventType | string | ✅ | The event type to listen for. | | callback | (eventData: any) => void | ✅ | The handler called when the event fires. |

Returns: { dispose(): void } — call dispose() to unsubscribe.

Vulnerability Reporting

The Guidelines for responsible disclosure details the procedure for disclosing security issues. Please do not report security vulnerabilities on the public issue tracker.

License

@strivacity/sdk-core is available under the MIT License. See the LICENSE file for more info.

Contributing

Please see our contributing guide.

Migrating to v3.0

Entry API Major Changes

Strivacity SDK's entry() API now returns a structured object instead of a plain string. Check the example above in the usage section for more details.