🎩 You're Invited:Meet the Socket team at Black Hat in Las Vegas, August 3-6.RSVP
Sign In

@shadowob/oauth

Package Overview
Dependencies
Maintainers
1
Versions
78
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@shadowob/oauth - npm Package Compare versions

Comparing version
0.4.0
to
0.4.1
+131
dist/index.cjs
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/index.ts
var index_exports = {};
__export(index_exports, {
ShadowOAuth: () => ShadowOAuth
});
module.exports = __toCommonJS(index_exports);
// src/client.ts
var DEFAULT_BASE_URL = "https://shadowob.com";
var ShadowOAuth = class {
baseUrl;
clientId;
clientSecret;
redirectUri;
constructor(config) {
this.baseUrl = (config.baseUrl ?? DEFAULT_BASE_URL).replace(/\/$/, "");
this.clientId = config.clientId;
this.clientSecret = config.clientSecret;
this.redirectUri = config.redirectUri;
}
/**
* Generate the authorization URL to redirect users to Shadow for login.
*/
getAuthorizeUrl(options) {
const scope = options?.scope?.join(" ") ?? "user:read";
const params = new URLSearchParams({
response_type: "code",
client_id: this.clientId,
redirect_uri: this.redirectUri,
scope
});
if (options?.state) {
params.set("state", options.state);
}
return `${this.baseUrl}/oauth/authorize?${params.toString()}`;
}
/**
* Exchange an authorization code for access and refresh tokens.
*/
async getToken(code) {
const res = await fetch(`${this.baseUrl}/api/oauth/token`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
grant_type: "authorization_code",
code,
client_id: this.clientId,
client_secret: this.clientSecret,
redirect_uri: this.redirectUri
})
});
if (!res.ok) {
const body = await res.text().catch(() => "");
throw new Error(`Shadow OAuth token exchange failed (${res.status}): ${body}`);
}
const data = await res.json();
return {
accessToken: data.access_token,
refreshToken: data.refresh_token,
expiresIn: data.expires_in,
tokenType: data.token_type,
scope: data.scope
};
}
/**
* Refresh an access token using a refresh token.
*/
async refreshToken(refreshToken) {
const res = await fetch(`${this.baseUrl}/api/oauth/token`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
grant_type: "refresh_token",
refresh_token: refreshToken,
client_id: this.clientId,
client_secret: this.clientSecret
})
});
if (!res.ok) {
const body = await res.text().catch(() => "");
throw new Error(`Shadow OAuth token refresh failed (${res.status}): ${body}`);
}
const data = await res.json();
return {
accessToken: data.access_token,
refreshToken: data.refresh_token,
expiresIn: data.expires_in,
tokenType: data.token_type,
scope: data.scope
};
}
/**
* Get the authenticated user's information using an access token.
*/
async getUser(accessToken) {
const res = await fetch(`${this.baseUrl}/api/oauth/userinfo`, {
headers: {
Authorization: `Bearer ${accessToken}`,
Accept: "application/json"
}
});
if (!res.ok) {
const body = await res.text().catch(() => "");
throw new Error(`Shadow OAuth userinfo failed (${res.status}): ${body}`);
}
return res.json();
}
};
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
ShadowOAuth
});
interface ShadowOAuthConfig {
/** Your app's client_id from Shadow Developer Portal */
clientId: string;
/** Your app's client_secret (keep server-side only) */
clientSecret: string;
/** The redirect URI registered with your app */
redirectUri: string;
/** Shadow API base URL (default: https://shadowob.com) */
baseUrl?: string;
}
interface ShadowOAuthTokens {
accessToken: string;
refreshToken: string;
expiresIn: number;
tokenType: string;
scope: string;
}
interface ShadowOAuthUser {
id: string;
username: string;
displayName: string | null;
avatarUrl: string | null;
email?: string;
}
type ShadowOAuthScope = 'user:read' | 'user:email';
/**
* Shadow OAuth SDK client.
*
* Use this in your server-side application to implement
* "Login with Shadow" via the OAuth 2.0 Authorization Code flow.
*
* @example
* ```ts
* const oauth = new ShadowOAuth({
* clientId: 'shadow_xxx',
* clientSecret: 'shsec_xxx',
* redirectUri: 'https://myapp.com/callback',
* })
*
* // Step 1: Generate the authorization URL and redirect the user
* const url = oauth.getAuthorizeUrl({ scope: ['user:read', 'user:email'] })
*
* // Step 2: After callback, exchange the code for tokens
* const tokens = await oauth.getToken(code)
*
* // Step 3: Get user info
* const user = await oauth.getUser(tokens.accessToken)
* ```
*/
declare class ShadowOAuth {
private baseUrl;
private clientId;
private clientSecret;
private redirectUri;
constructor(config: ShadowOAuthConfig);
/**
* Generate the authorization URL to redirect users to Shadow for login.
*/
getAuthorizeUrl(options?: {
scope?: ShadowOAuthScope[];
state?: string;
}): string;
/**
* Exchange an authorization code for access and refresh tokens.
*/
getToken(code: string): Promise<ShadowOAuthTokens>;
/**
* Refresh an access token using a refresh token.
*/
refreshToken(refreshToken: string): Promise<ShadowOAuthTokens>;
/**
* Get the authenticated user's information using an access token.
*/
getUser(accessToken: string): Promise<ShadowOAuthUser>;
}
export { ShadowOAuth, type ShadowOAuthConfig, type ShadowOAuthScope, type ShadowOAuthTokens, type ShadowOAuthUser };
interface ShadowOAuthConfig {
/** Your app's client_id from Shadow Developer Portal */
clientId: string;
/** Your app's client_secret (keep server-side only) */
clientSecret: string;
/** The redirect URI registered with your app */
redirectUri: string;
/** Shadow API base URL (default: https://shadowob.com) */
baseUrl?: string;
}
interface ShadowOAuthTokens {
accessToken: string;
refreshToken: string;
expiresIn: number;
tokenType: string;
scope: string;
}
interface ShadowOAuthUser {
id: string;
username: string;
displayName: string | null;
avatarUrl: string | null;
email?: string;
}
type ShadowOAuthScope = 'user:read' | 'user:email';
/**
* Shadow OAuth SDK client.
*
* Use this in your server-side application to implement
* "Login with Shadow" via the OAuth 2.0 Authorization Code flow.
*
* @example
* ```ts
* const oauth = new ShadowOAuth({
* clientId: 'shadow_xxx',
* clientSecret: 'shsec_xxx',
* redirectUri: 'https://myapp.com/callback',
* })
*
* // Step 1: Generate the authorization URL and redirect the user
* const url = oauth.getAuthorizeUrl({ scope: ['user:read', 'user:email'] })
*
* // Step 2: After callback, exchange the code for tokens
* const tokens = await oauth.getToken(code)
*
* // Step 3: Get user info
* const user = await oauth.getUser(tokens.accessToken)
* ```
*/
declare class ShadowOAuth {
private baseUrl;
private clientId;
private clientSecret;
private redirectUri;
constructor(config: ShadowOAuthConfig);
/**
* Generate the authorization URL to redirect users to Shadow for login.
*/
getAuthorizeUrl(options?: {
scope?: ShadowOAuthScope[];
state?: string;
}): string;
/**
* Exchange an authorization code for access and refresh tokens.
*/
getToken(code: string): Promise<ShadowOAuthTokens>;
/**
* Refresh an access token using a refresh token.
*/
refreshToken(refreshToken: string): Promise<ShadowOAuthTokens>;
/**
* Get the authenticated user's information using an access token.
*/
getUser(accessToken: string): Promise<ShadowOAuthUser>;
}
export { ShadowOAuth, type ShadowOAuthConfig, type ShadowOAuthScope, type ShadowOAuthTokens, type ShadowOAuthUser };
// src/client.ts
var DEFAULT_BASE_URL = "https://shadowob.com";
var ShadowOAuth = class {
baseUrl;
clientId;
clientSecret;
redirectUri;
constructor(config) {
this.baseUrl = (config.baseUrl ?? DEFAULT_BASE_URL).replace(/\/$/, "");
this.clientId = config.clientId;
this.clientSecret = config.clientSecret;
this.redirectUri = config.redirectUri;
}
/**
* Generate the authorization URL to redirect users to Shadow for login.
*/
getAuthorizeUrl(options) {
const scope = options?.scope?.join(" ") ?? "user:read";
const params = new URLSearchParams({
response_type: "code",
client_id: this.clientId,
redirect_uri: this.redirectUri,
scope
});
if (options?.state) {
params.set("state", options.state);
}
return `${this.baseUrl}/oauth/authorize?${params.toString()}`;
}
/**
* Exchange an authorization code for access and refresh tokens.
*/
async getToken(code) {
const res = await fetch(`${this.baseUrl}/api/oauth/token`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
grant_type: "authorization_code",
code,
client_id: this.clientId,
client_secret: this.clientSecret,
redirect_uri: this.redirectUri
})
});
if (!res.ok) {
const body = await res.text().catch(() => "");
throw new Error(`Shadow OAuth token exchange failed (${res.status}): ${body}`);
}
const data = await res.json();
return {
accessToken: data.access_token,
refreshToken: data.refresh_token,
expiresIn: data.expires_in,
tokenType: data.token_type,
scope: data.scope
};
}
/**
* Refresh an access token using a refresh token.
*/
async refreshToken(refreshToken) {
const res = await fetch(`${this.baseUrl}/api/oauth/token`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
grant_type: "refresh_token",
refresh_token: refreshToken,
client_id: this.clientId,
client_secret: this.clientSecret
})
});
if (!res.ok) {
const body = await res.text().catch(() => "");
throw new Error(`Shadow OAuth token refresh failed (${res.status}): ${body}`);
}
const data = await res.json();
return {
accessToken: data.access_token,
refreshToken: data.refresh_token,
expiresIn: data.expires_in,
tokenType: data.token_type,
scope: data.scope
};
}
/**
* Get the authenticated user's information using an access token.
*/
async getUser(accessToken) {
const res = await fetch(`${this.baseUrl}/api/oauth/userinfo`, {
headers: {
Authorization: `Bearer ${accessToken}`,
Accept: "application/json"
}
});
if (!res.ok) {
const body = await res.text().catch(() => "");
throw new Error(`Shadow OAuth userinfo failed (${res.status}): ${body}`);
}
return res.json();
}
};
export {
ShadowOAuth
};
+24
-4
{
"name": "@shadowob/oauth",
"version": "0.4.0",
"version": "0.4.1",
"description": "Shadow OAuth SDK — typed client for integrating Shadow OAuth login into third-party applications",
"type": "module",
"main": "./src/index.ts",
"types": "./src/index.ts",
"main": "./dist/index.js",
"module": "./dist/index.js",
"require": "./dist/index.cjs",
"types": "./dist/index.d.ts",
"exports": {
".": "./src/index.ts"
".": {
"types": "./dist/index.d.ts",
"development": "./src/index.ts",
"import": "./dist/index.js",
"require": "./dist/index.cjs",
"default": "./dist/index.js"
}
},
"files": [
"dist"
],
"dependencies": {},
"devDependencies": {
"tsup": "^8.5.0",
"typescript": "^5.9.3"
},
"publishConfig": {
"access": "public"
},
"scripts": {
"build": "tsup",
"dev": "tsup --watch",
"test": "vitest run",

@@ -14,0 +34,0 @@ "test:watch": "vitest"

-157
import type {
ShadowOAuthConfig,
ShadowOAuthScope,
ShadowOAuthTokens,
ShadowOAuthUser,
} from './types'
const DEFAULT_BASE_URL = 'https://shadowob.com'
/**
* Shadow OAuth SDK client.
*
* Use this in your server-side application to implement
* "Login with Shadow" via the OAuth 2.0 Authorization Code flow.
*
* @example
* ```ts
* const oauth = new ShadowOAuth({
* clientId: 'shadow_xxx',
* clientSecret: 'shsec_xxx',
* redirectUri: 'https://myapp.com/callback',
* })
*
* // Step 1: Generate the authorization URL and redirect the user
* const url = oauth.getAuthorizeUrl({ scope: ['user:read', 'user:email'] })
*
* // Step 2: After callback, exchange the code for tokens
* const tokens = await oauth.getToken(code)
*
* // Step 3: Get user info
* const user = await oauth.getUser(tokens.accessToken)
* ```
*/
export class ShadowOAuth {
private baseUrl: string
private clientId: string
private clientSecret: string
private redirectUri: string
constructor(config: ShadowOAuthConfig) {
this.baseUrl = (config.baseUrl ?? DEFAULT_BASE_URL).replace(/\/$/, '')
this.clientId = config.clientId
this.clientSecret = config.clientSecret
this.redirectUri = config.redirectUri
}
/**
* Generate the authorization URL to redirect users to Shadow for login.
*/
getAuthorizeUrl(options?: { scope?: ShadowOAuthScope[]; state?: string }): string {
const scope = options?.scope?.join(' ') ?? 'user:read'
const params = new URLSearchParams({
response_type: 'code',
client_id: this.clientId,
redirect_uri: this.redirectUri,
scope,
})
if (options?.state) {
params.set('state', options.state)
}
return `${this.baseUrl}/oauth/authorize?${params.toString()}`
}
/**
* Exchange an authorization code for access and refresh tokens.
*/
async getToken(code: string): Promise<ShadowOAuthTokens> {
const res = await fetch(`${this.baseUrl}/api/oauth/token`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
grant_type: 'authorization_code',
code,
client_id: this.clientId,
client_secret: this.clientSecret,
redirect_uri: this.redirectUri,
}),
})
if (!res.ok) {
const body = await res.text().catch(() => '')
throw new Error(`Shadow OAuth token exchange failed (${res.status}): ${body}`)
}
const data = (await res.json()) as {
access_token: string
refresh_token: string
expires_in: number
token_type: string
scope: string
}
return {
accessToken: data.access_token,
refreshToken: data.refresh_token,
expiresIn: data.expires_in,
tokenType: data.token_type,
scope: data.scope,
}
}
/**
* Refresh an access token using a refresh token.
*/
async refreshToken(refreshToken: string): Promise<ShadowOAuthTokens> {
const res = await fetch(`${this.baseUrl}/api/oauth/token`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
grant_type: 'refresh_token',
refresh_token: refreshToken,
client_id: this.clientId,
client_secret: this.clientSecret,
}),
})
if (!res.ok) {
const body = await res.text().catch(() => '')
throw new Error(`Shadow OAuth token refresh failed (${res.status}): ${body}`)
}
const data = (await res.json()) as {
access_token: string
refresh_token: string
expires_in: number
token_type: string
scope: string
}
return {
accessToken: data.access_token,
refreshToken: data.refresh_token,
expiresIn: data.expires_in,
tokenType: data.token_type,
scope: data.scope,
}
}
/**
* Get the authenticated user's information using an access token.
*/
async getUser(accessToken: string): Promise<ShadowOAuthUser> {
const res = await fetch(`${this.baseUrl}/api/oauth/userinfo`, {
headers: {
Authorization: `Bearer ${accessToken}`,
Accept: 'application/json',
},
})
if (!res.ok) {
const body = await res.text().catch(() => '')
throw new Error(`Shadow OAuth userinfo failed (${res.status}): ${body}`)
}
return res.json() as Promise<ShadowOAuthUser>
}
}
export { ShadowOAuth } from './client'
export type {
ShadowOAuthConfig,
ShadowOAuthScope,
ShadowOAuthTokens,
ShadowOAuthUser,
} from './types'
export interface ShadowOAuthConfig {
/** Your app's client_id from Shadow Developer Portal */
clientId: string
/** Your app's client_secret (keep server-side only) */
clientSecret: string
/** The redirect URI registered with your app */
redirectUri: string
/** Shadow API base URL (default: https://shadowob.com) */
baseUrl?: string
}
export interface ShadowOAuthTokens {
accessToken: string
refreshToken: string
expiresIn: number
tokenType: string
scope: string
}
export interface ShadowOAuthUser {
id: string
username: string
displayName: string | null
avatarUrl: string | null
email?: string
}
export type ShadowOAuthScope = 'user:read' | 'user:email'
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"rootDir": "./src",
"outDir": "./dist"
},
"include": ["src"]
}