New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

arctic

Package Overview
Dependencies
Maintainers
0
Versions
78
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

arctic - npm Package Compare versions

Comparing version 2.3.3 to 3.0.0

dist/providers/tiktok.d.ts

2

dist/index.d.ts

@@ -56,3 +56,3 @@ export { AmazonCognito } from "./providers/amazon-cognito.js";

export { OAuth2Tokens, generateCodeVerifier, generateState } from "./oauth2.js";
export { OAuth2RequestError, ArcticFetchError } from "./request.js";
export { OAuth2RequestError, ArcticFetchError, UnexpectedErrorResponseBodyError, UnexpectedResponseError } from "./request.js";
export { decodeIdToken } from "./oidc.js";

@@ -56,3 +56,3 @@ export { AmazonCognito } from "./providers/amazon-cognito.js";

export { OAuth2Tokens, generateCodeVerifier, generateState } from "./oauth2.js";
export { OAuth2RequestError, ArcticFetchError } from "./request.js";
export { OAuth2RequestError, ArcticFetchError, UnexpectedErrorResponseBodyError, UnexpectedResponseError } from "./request.js";
export { decodeIdToken } from "./oidc.js";

@@ -1,3 +0,3 @@

import { encodeBase64urlNoPadding } from "@oslojs/encoding";
import { sha256 } from "@oslojs/crypto/sha2";
import * as encoding from "@oslojs/encoding";
import * as sha2 from "@oslojs/crypto/sha2";
export class OAuth2Tokens {

@@ -55,4 +55,4 @@ data;

export function createS256CodeChallenge(codeVerifier) {
const codeChallengeBytes = sha256(new TextEncoder().encode(codeVerifier));
return encodeBase64urlNoPadding(codeChallengeBytes);
const codeChallengeBytes = sha2.sha256(new TextEncoder().encode(codeVerifier));
return encoding.encodeBase64urlNoPadding(codeChallengeBytes);
}

@@ -62,3 +62,3 @@ export function generateCodeVerifier() {

crypto.getRandomValues(randomValues);
return encodeBase64urlNoPadding(randomValues);
return encoding.encodeBase64urlNoPadding(randomValues);
}

@@ -68,3 +68,3 @@ export function generateState() {

crypto.getRandomValues(randomValues);
return encodeBase64urlNoPadding(randomValues);
return encoding.encodeBase64urlNoPadding(randomValues);
}

@@ -1,5 +0,5 @@

import { decodeJWT } from "@oslojs/jwt";
import * as jwt from "@oslojs/jwt";
export function decodeIdToken(idToken) {
try {
return decodeJWT(idToken);
return jwt.decodeJWT(idToken);
}

@@ -6,0 +6,0 @@ catch (e) {

@@ -18,3 +18,5 @@ import { createOAuth2Request, sendTokenRequest } from "../request.js";

url.searchParams.set("state", state);
url.searchParams.set("scope", scopes.join(" "));
if (scopes.length > 0) {
url.searchParams.set("scope", scopes.join(" "));
}
url.searchParams.set("redirect_uri", this.redirectURI);

@@ -21,0 +23,0 @@ return url;

@@ -6,10 +6,8 @@ import type { OAuth2Tokens } from "../oauth2.js";

private tokenRevocationEndpoint;
private clientId;
private clientSecret;
private redirectURI;
constructor(userPool: string, clientId: string, clientSecret: string, redirectURI: string);
private client;
constructor(domain: string, clientId: string, clientSecret: string | null, redirectURI: string);
createAuthorizationURL(state: string, codeVerifier: string, scopes: string[]): URL;
validateAuthorizationCode(code: string, codeVerifier: string): Promise<OAuth2Tokens>;
refreshAccessToken(refreshToken: string): Promise<OAuth2Tokens>;
refreshAccessToken(refreshToken: string, scopes: string[]): Promise<OAuth2Tokens>;
revokeToken(token: string): Promise<void>;
}

@@ -1,7 +0,2 @@

/*
While HTTP basic auth is supported when used without PKCE,
only client secret is supported when PKCE is used.
*/
import { createS256CodeChallenge } from "../oauth2.js";
import { createOAuth2Request, sendTokenRequest, sendTokenRevocationRequest } from "../request.js";
import { CodeChallengeMethod, OAuth2Client } from "../client.js";
export class AmazonCognito {

@@ -11,58 +6,24 @@ authorizationEndpoint;

tokenRevocationEndpoint;
clientId;
clientSecret;
redirectURI;
constructor(userPool, clientId, clientSecret, redirectURI) {
this.authorizationEndpoint = userPool + "/oauth2/authorize";
this.tokenEndpoint = userPool + "/oauth2/token";
this.tokenRevocationEndpoint = userPool + "/oauth2/revoke";
this.clientId = clientId;
this.clientSecret = clientSecret;
this.redirectURI = redirectURI;
client;
constructor(domain, clientId, clientSecret, redirectURI) {
this.authorizationEndpoint = `https://${domain}/oauth2/authorize`;
this.tokenEndpoint = `https://${domain}/oauth2/token`;
this.tokenRevocationEndpoint = `https://${domain}/oauth2/revoke`;
this.client = new OAuth2Client(clientId, clientSecret, redirectURI);
}
createAuthorizationURL(state, codeVerifier, scopes) {
const url = new URL(this.authorizationEndpoint);
url.searchParams.set("response_type", "code");
url.searchParams.set("client_id", this.clientId);
url.searchParams.set("redirect_uri", this.redirectURI);
url.searchParams.set("state", state);
const codeChallenge = createS256CodeChallenge(codeVerifier);
url.searchParams.set("code_challenge_method", "S256");
url.searchParams.set("code_challenge", codeChallenge);
if (scopes.length > 0) {
url.searchParams.set("scope", scopes.join(" "));
}
const url = this.client.createAuthorizationURLWithPKCE(this.authorizationEndpoint, state, CodeChallengeMethod.S256, codeVerifier, scopes);
return url;
}
async validateAuthorizationCode(code, codeVerifier) {
const body = new URLSearchParams();
body.set("grant_type", "authorization_code");
body.set("code", code);
body.set("redirect_uri", this.redirectURI);
body.set("code_verifier", codeVerifier);
body.set("client_id", this.clientId);
body.set("client_secret", this.clientSecret);
const request = createOAuth2Request(this.tokenEndpoint, body);
const tokens = await sendTokenRequest(request);
const tokens = await this.client.validateAuthorizationCode(this.tokenEndpoint, code, codeVerifier);
return tokens;
}
// TODO: Add `scopes` parameter
async refreshAccessToken(refreshToken) {
const body = new URLSearchParams();
body.set("grant_type", "refresh_token");
body.set("refresh_token", refreshToken);
body.set("client_id", this.clientId);
body.set("client_secret", this.clientSecret);
const request = createOAuth2Request(this.tokenEndpoint, body);
const tokens = await sendTokenRequest(request);
async refreshAccessToken(refreshToken, scopes) {
const tokens = await this.client.refreshAccessToken(this.tokenEndpoint, refreshToken, scopes);
return tokens;
}
async revokeToken(token) {
const body = new URLSearchParams();
body.set("token", token);
body.set("client_id", this.clientId);
body.set("client_secret", this.clientSecret);
const request = createOAuth2Request(this.tokenRevocationEndpoint, body);
await sendTokenRevocationRequest(request);
await this.client.revokeToken(this.tokenRevocationEndpoint, token);
}
}

@@ -0,3 +1,3 @@

import * as jwt from "@oslojs/jwt";
import { createOAuth2Request, sendTokenRequest } from "../request.js";
import { createJWTSignatureMessage, encodeJWT } from "@oslojs/jwt";
const authorizationEndpoint = "https://appleid.apple.com/auth/authorize";

@@ -23,3 +23,5 @@ const tokenEndpoint = "https://appleid.apple.com/auth/token";

url.searchParams.set("state", state);
url.searchParams.set("scope", scopes.join(" "));
if (scopes.length > 0) {
url.searchParams.set("scope", scopes.join(" "));
}
url.searchParams.set("redirect_uri", this.redirectURI);

@@ -61,6 +63,6 @@ return url;

hash: "SHA-256"
}, privateKey, createJWTSignatureMessage(headerJSON, payloadJSON)));
const jwt = encodeJWT(headerJSON, payloadJSON, signature);
return jwt;
}, privateKey, jwt.createJWTSignatureMessage(headerJSON, payloadJSON)));
const token = jwt.encodeJWT(headerJSON, payloadJSON, signature);
return token;
}
}

@@ -18,3 +18,5 @@ import { createOAuth2Request, sendTokenRequest } from "../request.js";

url.searchParams.set("state", state);
url.searchParams.set("scope", scopes.join(" "));
if (scopes.length > 0) {
url.searchParams.set("scope", scopes.join(" "));
}
url.searchParams.set("redirect_uri", this.redirectURI);

@@ -21,0 +23,0 @@ url.searchParams.set("audience", "api.atlassian.com");

@@ -7,7 +7,7 @@ import type { OAuth2Tokens } from "../oauth2.js";

private client;
constructor(domain: string, clientId: string, clientSecret: string, redirectURI: string);
createAuthorizationURL(state: string, scopes: string[]): URL;
validateAuthorizationCode(code: string): Promise<OAuth2Tokens>;
constructor(domain: string, clientId: string, clientSecret: string | null, redirectURI: string);
createAuthorizationURL(state: string, codeVerifier: string | null, scopes: string[]): URL;
validateAuthorizationCode(code: string, codeVerifier: string | null): Promise<OAuth2Tokens>;
refreshAccessToken(refreshToken: string): Promise<OAuth2Tokens>;
revokeToken(token: string): Promise<void>;
}

@@ -1,2 +0,2 @@

import { OAuth2Client } from "../client.js";
import { CodeChallengeMethod, OAuth2Client } from "../client.js";
export class Auth0 {

@@ -13,8 +13,14 @@ authorizationEndpoint;

}
createAuthorizationURL(state, scopes) {
const url = this.client.createAuthorizationURL(this.authorizationEndpoint, state, scopes);
createAuthorizationURL(state, codeVerifier, scopes) {
let url;
if (codeVerifier !== null) {
url = this.client.createAuthorizationURLWithPKCE(this.authorizationEndpoint, state, CodeChallengeMethod.S256, codeVerifier, scopes);
}
else {
url = this.client.createAuthorizationURL(this.authorizationEndpoint, state, scopes);
}
return url;
}
async validateAuthorizationCode(code) {
const tokens = await this.client.validateAuthorizationCode(this.tokenEndpoint, code, null);
async validateAuthorizationCode(code, codeVerifier) {
const tokens = await this.client.validateAuthorizationCode(this.tokenEndpoint, code, codeVerifier);
return tokens;

@@ -21,0 +27,0 @@ }

@@ -7,3 +7,3 @@ import type { OAuth2Tokens } from "../oauth2.js";

private client;
constructor(domain: string, clientId: string, clientSecret: string, redirectURI: string);
constructor(baseURL: string, clientId: string, clientSecret: string | null, redirectURI: string);
createAuthorizationURL(state: string, codeVerifier: string, scopes: string[]): URL;

@@ -10,0 +10,0 @@ validateAuthorizationCode(code: string, codeVerifier: string): Promise<OAuth2Tokens>;

import { CodeChallengeMethod, OAuth2Client } from "../client.js";
import { joinURIAndPath } from "../request.js";
export class Authentik {

@@ -7,6 +8,6 @@ authorizationEndpoint;

client;
constructor(domain, clientId, clientSecret, redirectURI) {
this.authorizationEndpoint = `https://${domain}/application/o/authorize/`;
this.tokenEndpoint = `https://${domain}/application/o/token/`;
this.tokenRevocationEndpoint = `https://${domain}/application/o/revoke`;
constructor(baseURL, clientId, clientSecret, redirectURI) {
this.authorizationEndpoint = joinURIAndPath(baseURL, "/application/o/authorize");
this.tokenEndpoint = joinURIAndPath(baseURL, "/application/o/token");
this.tokenRevocationEndpoint = joinURIAndPath(baseURL, "/application/o/revoke");
this.client = new OAuth2Client(clientId, clientSecret, redirectURI);

@@ -13,0 +14,0 @@ }

@@ -19,3 +19,5 @@ import { createOAuth2Request, sendTokenRequest, sendTokenRevocationRequest } from "../request.js";

url.searchParams.set("state", state);
url.searchParams.set("scope", scopes.join(" "));
if (scopes.length > 0) {
url.searchParams.set("scope", scopes.join(" "));
}
url.searchParams.set("redirect_uri", this.redirectURI);

@@ -22,0 +24,0 @@ return url;

import type { OAuth2Tokens } from "../oauth2.js";
export declare class Bungie {
private client;
constructor(clientId: string, clientSecret: string, redirectURI: string);
constructor(clientId: string, clientSecret: string | null, redirectURI: string);
createAuthorizationURL(state: string, scopes: string[]): URL;

@@ -6,0 +6,0 @@ validateAuthorizationCode(code: string): Promise<OAuth2Tokens>;

@@ -19,3 +19,5 @@ import { createOAuth2Request, sendTokenRequest, sendTokenRevocationRequest } from "../request.js";

url.searchParams.set("state", state);
url.searchParams.set("scope", scopes.join(" "));
if (scopes.length > 0) {
url.searchParams.set("scope", scopes.join(" "));
}
url.searchParams.set("redirect_uri", this.redirectURI);

@@ -22,0 +24,0 @@ return url;

import type { OAuth2Tokens } from "../oauth2.js";
export declare class Discord {
private client;
constructor(clientId: string, clientSecret: string, redirectURI: string);
createAuthorizationURL(state: string, scopes: string[]): URL;
validateAuthorizationCode(code: string): Promise<OAuth2Tokens>;
constructor(clientId: string, clientSecret: string | null, redirectURI: string);
createAuthorizationURL(state: string, codeVerifier: string | null, scopes: string[]): URL;
validateAuthorizationCode(code: string, codeVerifier: string | null): Promise<OAuth2Tokens>;
refreshAccessToken(refreshToken: string): Promise<OAuth2Tokens>;
revokeToken(token: string): Promise<void>;
}

@@ -1,2 +0,2 @@

import { OAuth2Client } from "../client.js";
import { CodeChallengeMethod, OAuth2Client } from "../client.js";
const authorizationEndpoint = "https://discord.com/oauth2/authorize";

@@ -10,8 +10,14 @@ const tokenEndpoint = "https://discord.com/api/oauth2/token";

}
createAuthorizationURL(state, scopes) {
const url = this.client.createAuthorizationURL(authorizationEndpoint, state, scopes);
createAuthorizationURL(state, codeVerifier, scopes) {
let url;
if (codeVerifier !== null) {
url = this.client.createAuthorizationURLWithPKCE(authorizationEndpoint, state, CodeChallengeMethod.S256, codeVerifier, scopes);
}
else {
url = this.client.createAuthorizationURL(authorizationEndpoint, state, scopes);
}
return url;
}
async validateAuthorizationCode(code) {
const tokens = await this.client.validateAuthorizationCode(tokenEndpoint, code, null);
async validateAuthorizationCode(code, codeVerifier) {
const tokens = await this.client.validateAuthorizationCode(tokenEndpoint, code, codeVerifier);
return tokens;

@@ -18,0 +24,0 @@ }

@@ -18,3 +18,5 @@ import { createOAuth2Request, sendTokenRequest } from "../request.js";

url.searchParams.set("state", state);
url.searchParams.set("scope", scopes.join(" "));
if (scopes.length > 0) {
url.searchParams.set("scope", scopes.join(" "));
}
url.searchParams.set("redirect_uri", this.redirectURI);

@@ -21,0 +23,0 @@ return url;

import type { OAuth2Tokens } from "../oauth2.js";
export declare class Etsy {
private client;
constructor(clientId: string, _ignore: any, redirectURI: string);
constructor(clientId: string, redirectURI: string);
createAuthorizationURL(state: string, codeVerifier: string, scopes: string[]): URL;

@@ -6,0 +6,0 @@ validateAuthorizationCode(code: string, codeVerifier: string): Promise<OAuth2Tokens>;

@@ -6,4 +6,3 @@ import { CodeChallengeMethod, OAuth2Client } from "../client.js";

client;
// v3: Remove `_ignore`
constructor(clientId, _ignore, redirectURI) {
constructor(clientId, redirectURI) {
this.client = new OAuth2Client(clientId, null, redirectURI);

@@ -10,0 +9,0 @@ }

@@ -18,3 +18,5 @@ import { createOAuth2Request, sendTokenRequest } from "../request.js";

url.searchParams.set("state", state);
url.searchParams.set("scope", scopes.join(" "));
if (scopes.length > 0) {
url.searchParams.set("scope", scopes.join(" "));
}
url.searchParams.set("redirect_uri", this.redirectURI);

@@ -21,0 +23,0 @@ return url;

@@ -1,2 +0,2 @@

import type { OAuth2Tokens } from "../oauth2.js";
import { OAuth2Tokens } from "../oauth2.js";
export declare class GitHub {

@@ -3,0 +3,0 @@ private clientId;

@@ -1,2 +0,3 @@

import { createOAuth2Request, encodeBasicCredentials, sendTokenRequest } from "../request.js";
import { ArcticFetchError, createOAuth2Request, createOAuth2RequestError, encodeBasicCredentials, UnexpectedErrorResponseBodyError, UnexpectedResponseError } from "../request.js";
import { OAuth2Tokens } from "../oauth2.js";
const authorizationEndpoint = "https://github.com/login/oauth/authorize";

@@ -18,3 +19,5 @@ const tokenEndpoint = "https://github.com/login/oauth/access_token";

url.searchParams.set("state", state);
url.searchParams.set("scope", scopes.join(" "));
if (scopes.length > 0) {
url.searchParams.set("scope", scopes.join(" "));
}
if (this.redirectURI !== null) {

@@ -49,1 +52,38 @@ url.searchParams.set("redirect_uri", this.redirectURI);

}
async function sendTokenRequest(request) {
let response;
try {
response = await fetch(request);
}
catch (e) {
throw new ArcticFetchError(e);
}
if (response.status !== 200) {
if (response.body !== null) {
await response.body.cancel();
}
throw new UnexpectedResponseError(response.status);
}
let data;
try {
data = await response.json();
}
catch {
throw new UnexpectedResponseError(response.status);
}
if (typeof data !== "object" || data === null) {
throw new UnexpectedErrorResponseBodyError(response.status, data);
}
if ("error" in data && typeof data.error === "string") {
let error;
try {
error = createOAuth2RequestError(data);
}
catch {
throw new UnexpectedErrorResponseBodyError(response.status, data);
}
throw error;
}
const tokens = new OAuth2Tokens(data);
return tokens;
}

@@ -7,3 +7,3 @@ import type { OAuth2Tokens } from "../oauth2.js";

private client;
constructor(domain: string, clientId: string, clientSecret: string, redirectURI: string);
constructor(baseURL: string, clientId: string, clientSecret: string | null, redirectURI: string);
createAuthorizationURL(state: string, scopes: string[]): URL;

@@ -10,0 +10,0 @@ validateAuthorizationCode(code: string): Promise<OAuth2Tokens>;

import { OAuth2Client } from "../client.js";
import { joinURIAndPath } from "../request.js";
export class GitLab {

@@ -7,6 +8,6 @@ authorizationEndpoint;

client;
constructor(domain, clientId, clientSecret, redirectURI) {
this.authorizationEndpoint = `https://${domain}/oauth/authorize`;
this.tokenEndpoint = `https://${domain}/oauth/token`;
this.tokenRevocationEndpoint = `https://${domain}/oauth/revoke`;
constructor(baseURL, clientId, clientSecret, redirectURI) {
this.authorizationEndpoint = joinURIAndPath(baseURL, "/oauth/authorize");
this.tokenEndpoint = joinURIAndPath(baseURL, "/oauth/token");
this.tokenRevocationEndpoint = joinURIAndPath(baseURL, "/oauth/revoke");
this.client = new OAuth2Client(clientId, clientSecret, redirectURI);

@@ -13,0 +14,0 @@ }

@@ -18,3 +18,5 @@ import { createOAuth2Request, sendTokenRequest } from "../request.js";

url.searchParams.set("state", state);
url.searchParams.set("scope", scopes.join(" "));
if (scopes.length > 0) {
url.searchParams.set("scope", scopes.join(" "));
}
url.searchParams.set("redirect_uri", this.redirectURI);

@@ -21,0 +23,0 @@ return url;

@@ -7,3 +7,3 @@ import type { OAuth2Tokens } from "../oauth2.js";

private client;
constructor(realmURL: string, clientId: string, clientSecret: string, redirectURI: string);
constructor(realmURL: string, clientId: string, clientSecret: string | null, redirectURI: string);
createAuthorizationURL(state: string, codeVerifier: string, scopes: string[]): URL;

@@ -10,0 +10,0 @@ validateAuthorizationCode(code: string, codeVerifier: string): Promise<OAuth2Tokens>;

@@ -19,3 +19,5 @@ import { createS256CodeChallenge } from "../oauth2.js";

url.searchParams.set("state", state);
url.searchParams.set("scope", scopes.join(" "));
if (scopes.length > 0) {
url.searchParams.set("scope", scopes.join(" "));
}
url.searchParams.set("redirect_uri", this.redirectURI);

@@ -22,0 +24,0 @@ const codeChallenge = createS256CodeChallenge(codeVerifier);

@@ -18,3 +18,5 @@ import { createOAuth2Request, sendTokenRequest } from "../request.js";

url.searchParams.set("state", state);
url.searchParams.set("scope", scopes.join(" "));
if (scopes.length > 0) {
url.searchParams.set("scope", scopes.join(" "));
}
url.searchParams.set("redirect_uri", this.redirectURI);

@@ -21,0 +23,0 @@ return url;

@@ -19,3 +19,5 @@ // LinkedIn doesn't seem to support HTTP Basic Auth

url.searchParams.set("state", state);
url.searchParams.set("scope", scopes.join(" "));
if (scopes.length > 0) {
url.searchParams.set("scope", scopes.join(" "));
}
url.searchParams.set("redirect_uri", this.redirectURI);

@@ -22,0 +24,0 @@ return url;

@@ -6,6 +6,6 @@ import type { OAuth2Tokens } from "../oauth2.js";

private client;
constructor(tenant: string, clientId: string, clientSecret: string, redirectURI: string);
constructor(tenant: string, clientId: string, clientSecret: string | null, redirectURI: string);
createAuthorizationURL(state: string, codeVerifier: string, scopes: string[]): URL;
validateAuthorizationCode(code: string, codeVerifier: string): Promise<OAuth2Tokens>;
refreshAccessToken(refreshToken: string): Promise<OAuth2Tokens>;
refreshAccessToken(refreshToken: string, scopes: string[]): Promise<OAuth2Tokens>;
}
import { CodeChallengeMethod, OAuth2Client } from "../client.js";
import { joinURIAndPath } from "../request.js";
export class MicrosoftEntraId {

@@ -7,4 +8,4 @@ authorizationEndpoint;

constructor(tenant, clientId, clientSecret, redirectURI) {
this.authorizationEndpoint = `https://login.microsoftonline.com/${tenant}/oauth2/v2.0/authorize`;
this.tokenEndpoint = `https://login.microsoftonline.com/${tenant}/oauth2/v2.0/token`;
this.authorizationEndpoint = joinURIAndPath("https://login.microsoftonline.com", tenant, "/oauth2/v2.0/authorize");
this.tokenEndpoint = joinURIAndPath("https://login.microsoftonline.com", tenant, "/oauth2/v2.0/token");
this.client = new OAuth2Client(clientId, clientSecret, redirectURI);

@@ -20,7 +21,6 @@ }

}
// v3 TODO: Add `scopes` parameter
async refreshAccessToken(refreshToken) {
const tokens = await this.client.refreshAccessToken(this.tokenEndpoint, refreshToken, []);
async refreshAccessToken(refreshToken, scopes) {
const tokens = await this.client.refreshAccessToken(this.tokenEndpoint, refreshToken, scopes);
return tokens;
}
}
import type { OAuth2Tokens } from "../oauth2.js";
export declare class MyAnimeList {
private client;
constructor(clientId: string, clientSecret: string, options?: {
redirectURI?: string;
});
constructor(clientId: string, clientSecret: string, redirectURI: string | null);
createAuthorizationURL(state: string, codeVerifier: string): URL;

@@ -8,0 +6,0 @@ validateAuthorizationCode(code: string, codeVerifier: string): Promise<OAuth2Tokens>;

@@ -6,5 +6,4 @@ import { OAuth2Client, CodeChallengeMethod } from "../client.js";

client;
// v3 TODO: fix
constructor(clientId, clientSecret, options) {
this.client = new OAuth2Client(clientId, clientSecret, options?.redirectURI ?? null);
constructor(clientId, clientSecret, redirectURI) {
this.client = new OAuth2Client(clientId, clientSecret, redirectURI);
}

@@ -11,0 +10,0 @@ createAuthorizationURL(state, codeVerifier) {

import { CodeChallengeMethod, OAuth2Client } from "../client.js";
import { joinURIAndPath } from "../request.js";
export class Okta {

@@ -10,7 +11,7 @@ authorizationEndpoint;

if (authorizationServerId !== null) {
baseURL = baseURL + `/${authorizationServerId}`;
baseURL = joinURIAndPath(baseURL, authorizationServerId);
}
this.authorizationEndpoint = baseURL + "/v1/authorize";
this.tokenEndpoint = baseURL + "/v1/token";
this.tokenRevocationEndpoint = baseURL + "/v1/revoke";
this.authorizationEndpoint = joinURIAndPath(baseURL, "/v1/authorize");
this.tokenEndpoint = joinURIAndPath(baseURL, "/v1/token");
this.tokenRevocationEndpoint = joinURIAndPath(baseURL, "/v1/revoke");
this.client = new OAuth2Client(clientId, clientSecret, redirectURI);

@@ -17,0 +18,0 @@ }

@@ -18,3 +18,5 @@ import { createOAuth2Request, sendTokenRequest } from "../request.js";

url.searchParams.set("state", state);
url.searchParams.set("scope", scopes.join(" "));
if (scopes.length > 0) {
url.searchParams.set("scope", scopes.join(" "));
}
if (this.redirectURI !== null) {

@@ -21,0 +23,0 @@ url.searchParams.set("redirect_uri", this.redirectURI);

@@ -18,3 +18,5 @@ import { createOAuth2Request, sendTokenRequest } from "../request.js";

url.searchParams.set("state", state);
url.searchParams.set("scope", scopes.join(" "));
if (scopes.length > 0) {
url.searchParams.set("scope", scopes.join(" "));
}
url.searchParams.set("redirect_uri", this.redirectURI);

@@ -21,0 +23,0 @@ return url;

import type { OAuth2Tokens } from "../oauth2.js";
export declare class Roblox {
private client;
constructor(clientId: string, clientSecret: string, redirectURI: string);
constructor(clientId: string, clientSecret: string | null, redirectURI: string);
createAuthorizationURL(state: string, codeVerifier: string, scopes: string[]): URL;

@@ -6,0 +6,0 @@ validateAuthorizationCode(code: string, codeVerifier: string): Promise<OAuth2Tokens>;

@@ -7,3 +7,3 @@ import type { OAuth2Tokens } from "../oauth2.js";

private client;
constructor(domain: string, clientId: string, clientSecret: string, redirectURI: string);
constructor(domain: string, clientId: string, clientSecret: string | null, redirectURI: string);
createAuthorizationURL(state: string, codeVerifier: string, scopes: string[]): URL;

@@ -10,0 +10,0 @@ validateAuthorizationCode(code: string, codeVerifier: string): Promise<OAuth2Tokens>;

import type { OAuth2Tokens } from "../oauth2.js";
export declare class Spotify {
private client;
constructor(clientId: string, clientSecret: string, redirectURI: string);
createAuthorizationURL(state: string, scopes: string[]): URL;
validateAuthorizationCode(code: string): Promise<OAuth2Tokens>;
constructor(clientId: string, clientSecret: string | null, redirectURI: string);
createAuthorizationURL(state: string, codeVerifier: string | null, scopes: string[]): URL;
validateAuthorizationCode(code: string, codeVerifier: string | null): Promise<OAuth2Tokens>;
refreshAccessToken(refreshToken: string): Promise<OAuth2Tokens>;
}

@@ -1,2 +0,2 @@

import { OAuth2Client } from "../client.js";
import { CodeChallengeMethod, OAuth2Client } from "../client.js";
const authorizationEndpoint = "https://accounts.spotify.com/authorize";

@@ -9,8 +9,14 @@ const tokenEndpoint = "https://accounts.spotify.com/api/token";

}
createAuthorizationURL(state, scopes) {
const url = this.client.createAuthorizationURL(authorizationEndpoint, state, scopes);
createAuthorizationURL(state, codeVerifier, scopes) {
let url;
if (codeVerifier !== null) {
url = this.client.createAuthorizationURLWithPKCE(authorizationEndpoint, state, CodeChallengeMethod.S256, codeVerifier, scopes);
}
else {
url = this.client.createAuthorizationURL(authorizationEndpoint, state, scopes);
}
return url;
}
async validateAuthorizationCode(code) {
const tokens = await this.client.validateAuthorizationCode(tokenEndpoint, code, null);
async validateAuthorizationCode(code, codeVerifier) {
const tokens = await this.client.validateAuthorizationCode(tokenEndpoint, code, codeVerifier);
return tokens;

@@ -17,0 +23,0 @@ }

@@ -19,3 +19,5 @@ import { createOAuth2Request, sendTokenRequest } from "../request.js";

url.searchParams.set("state", state);
url.searchParams.set("scope", scopes.join(" "));
if (scopes.length > 0) {
url.searchParams.set("scope", scopes.join(" "));
}
url.searchParams.set("redirect_uri", this.redirectURI);

@@ -31,3 +33,5 @@ return url;

body.set("client_secret", this.clientSecret);
body.set("scope", scopes.join(" "));
if (scopes.length > 0) {
body.set("scope", scopes.join(" "));
}
const request = createOAuth2Request(tokenEndpoint, body);

@@ -44,3 +48,5 @@ const tokens = await sendTokenRequest(request);

body.set("client_secret", this.clientSecret);
body.set("scope", scopes.join(" "));
if (scopes.length > 0) {
body.set("scope", scopes.join(" "));
}
const request = createOAuth2Request(refreshEndpoint, body);

@@ -47,0 +53,0 @@ const tokens = await sendTokenRequest(request);

@@ -18,3 +18,6 @@ import { createOAuth2Request, sendTokenRequest } from "../request.js";

url.searchParams.set("state", state);
url.searchParams.set("scope", scopes.join(" "));
// Strava deviates from the RFC and uses a comma-delimitated string instead of space.
if (scopes.length > 0) {
url.searchParams.set("scope", scopes.join(","));
}
url.searchParams.set("redirect_uri", this.redirectURI);

@@ -21,0 +24,0 @@ return url;

@@ -18,3 +18,5 @@ import { createOAuth2Request, sendTokenRequest } from "../request.js";

url.searchParams.set("state", state);
url.searchParams.set("scope", scopes.join(" "));
if (scopes.length > 0) {
url.searchParams.set("scope", scopes.join(" "));
}
url.searchParams.set("redirect_uri", this.redirectURI);

@@ -21,0 +23,0 @@ return url;

@@ -19,3 +19,5 @@ // Does not support HTTP Basic Auth scheme.

url.searchParams.set("state", state);
url.searchParams.set("scope", scopes.join(" "));
if (scopes.length > 0) {
url.searchParams.set("scope", scopes.join(" "));
}
url.searchParams.set("redirect_uri", this.redirectURI);

@@ -22,0 +24,0 @@ return url;

import type { OAuth2Tokens } from "../oauth2.js";
export declare class Twitter {
private client;
constructor(clientId: string, clientSecret: string, redirectURI: string);
constructor(clientId: string, clientSecret: string | null, redirectURI: string);
createAuthorizationURL(state: string, codeVerifier: string, scopes: string[]): URL;

@@ -6,0 +6,0 @@ validateAuthorizationCode(code: string, codeVerifier: string): Promise<OAuth2Tokens>;

@@ -18,3 +18,5 @@ import { createOAuth2Request, sendTokenRequest } from "../request.js";

url.searchParams.set("state", state);
url.searchParams.set("scope", scopes.join(" "));
if (scopes.length > 0) {
url.searchParams.set("scope", scopes.join(" "));
}
url.searchParams.set("redirect_uri", this.redirectURI);

@@ -21,0 +23,0 @@ return url;

@@ -1,2 +0,2 @@

import type { OAuth2Tokens } from "../oauth2.js";
import { type OAuth2Tokens } from "../oauth2.js";
export declare class WorkOS {

@@ -6,5 +6,5 @@ private clientId;

private redirectURI;
constructor(clientId: string, clientSecret: string, redirectURI: string);
createAuthorizationURL(state: string): URL;
validateAuthorizationCode(code: string): Promise<OAuth2Tokens>;
constructor(clientId: string, clientSecret: string | null, redirectURI: string);
createAuthorizationURL(state: string, codeVerifier: string | null): URL;
validateAuthorizationCode(code: string, codeVerifier: string | null): Promise<OAuth2Tokens>;
}
import { createOAuth2Request, sendTokenRequest } from "../request.js";
import { createS256CodeChallenge } from "../oauth2.js";
const authorizationEndpoint = "https://api.workos.com/sso/authorize";

@@ -13,3 +14,3 @@ const tokenEndpoint = "https://api.workos.com/sso/token";

}
createAuthorizationURL(state) {
createAuthorizationURL(state, codeVerifier) {
const url = new URL(authorizationEndpoint);

@@ -20,5 +21,10 @@ url.searchParams.set("response_type", "code");

url.searchParams.set("redirect_uri", this.redirectURI);
if (codeVerifier !== null) {
const codeChallenge = createS256CodeChallenge(codeVerifier);
url.searchParams.set("code_challenge_method", "S256");
url.searchParams.set("code_challenge", codeChallenge);
}
return url;
}
async validateAuthorizationCode(code) {
async validateAuthorizationCode(code, codeVerifier) {
const body = new URLSearchParams();

@@ -29,3 +35,8 @@ body.set("grant_type", "authorization_code");

body.set("client_id", this.clientId);
body.set("client_secret", this.clientSecret);
if (this.clientSecret !== null) {
body.set("client_secret", this.clientSecret);
}
if (codeVerifier !== null) {
body.set("code_verifier", codeVerifier);
}
const request = createOAuth2Request(tokenEndpoint, body);

@@ -32,0 +43,0 @@ const tokens = await sendTokenRequest(request);

import { OAuth2Tokens } from "./oauth2.js";
export declare function joinURIAndPath(base: string, ...path: string[]): string;
export declare function createOAuth2Request(endpoint: string, body: URLSearchParams): Request;

@@ -6,2 +7,3 @@ export declare function encodeBasicCredentials(username: string, password: string): string;

export declare function sendTokenRevocationRequest(request: Request): Promise<void>;
export declare function createOAuth2RequestError(result: object): OAuth2RequestError;
export declare class ArcticFetchError extends Error {

@@ -17,1 +19,10 @@ constructor(cause: unknown);

}
export declare class UnexpectedResponseError extends Error {
status: number;
constructor(responseStatus: number);
}
export declare class UnexpectedErrorResponseBodyError extends Error {
status: number;
data: unknown;
constructor(status: number, data: unknown);
}

@@ -1,3 +0,12 @@

import { encodeBase64 } from "@oslojs/encoding";
import * as encoding from "@oslojs/encoding";
import { OAuth2Tokens } from "./oauth2.js";
import { trimLeft, trimRight } from "./utils.js";
export function joinURIAndPath(base, ...path) {
let joined = trimRight(base, "/");
for (const part of path) {
joined += "/";
joined += trimRight(trimLeft(part, "/"), "/");
}
return joined;
}
export function createOAuth2Request(endpoint, body) {

@@ -19,3 +28,3 @@ const bodyBytes = new TextEncoder().encode(body.toString());

const bytes = new TextEncoder().encode(`${username}:${password}`);
return encodeBase64(bytes);
return encoding.encodeBase64(bytes);
}

@@ -30,17 +39,40 @@ export async function sendTokenRequest(request) {

}
let data;
try {
data = await response.json();
if (response.status === 400 || response.status === 401) {
let data;
try {
data = await response.json();
}
catch {
throw new UnexpectedResponseError(response.status);
}
if (typeof data !== "object" || data === null) {
throw new UnexpectedErrorResponseBodyError(response.status, data);
}
let error;
try {
error = createOAuth2RequestError(data);
}
catch {
throw new UnexpectedErrorResponseBodyError(response.status, data);
}
throw error;
}
catch {
throw new Error("Failed to parse response body");
if (response.status === 200) {
let data;
try {
data = await response.json();
}
catch {
throw new UnexpectedResponseError(response.status);
}
if (typeof data !== "object" || data === null) {
throw new UnexpectedErrorResponseBodyError(response.status, data);
}
const tokens = new OAuth2Tokens(data);
return tokens;
}
if (typeof data !== "object" || data === null) {
throw new Error("Unexpected response body data");
if (response.body !== null) {
await response.body.cancel();
}
if ("error" in data && typeof data.error === "string") {
const error = createOAuth2RequestError(data);
throw error;
}
return new OAuth2Tokens(data);
throw new UnexpectedResponseError(response.status);
}

@@ -55,21 +87,34 @@ export async function sendTokenRevocationRequest(request) {

}
if (response.ok) {
if (response.status === 400 || response.status === 401) {
let data;
try {
data = await response.json();
}
catch {
throw new UnexpectedErrorResponseBodyError(response.status, null);
}
if (typeof data !== "object" || data === null) {
throw new UnexpectedErrorResponseBodyError(response.status, data);
}
let error;
try {
error = createOAuth2RequestError(data);
}
catch {
throw new UnexpectedErrorResponseBodyError(response.status, data);
}
throw error;
}
if (response.status === 200) {
if (response.body !== null) {
await response.body.cancel();
}
return;
}
let data;
try {
data = await response.json();
if (response.body !== null) {
await response.body.cancel();
}
catch {
throw new Error("Failed to parse response body");
}
if (typeof data !== "object" || data === null) {
throw new Error("Unexpected response body data");
}
if ("error" in data && typeof data.error === "string") {
const error = createOAuth2RequestError(data);
throw error;
}
throw new UnexpectedResponseError(response.status);
}
function createOAuth2RequestError(result) {
export function createOAuth2RequestError(result) {
let code;

@@ -85,12 +130,22 @@ if ("error" in result && typeof result.error === "string") {

let state = null;
if ("error_description" in result && typeof result.error_description === "string") {
if ("error_description" in result) {
if (typeof result.error_description !== "string") {
throw new Error("Invalid data");
}
description = result.error_description;
}
if ("error_uri" in result && typeof result.error_uri === "string") {
if ("error_uri" in result) {
if (typeof result.error_uri !== "string") {
throw new Error("Invalid data");
}
uri = result.error_uri;
}
if ("state" in result && typeof result.state === "string") {
if ("state" in result) {
if (typeof result.state !== "string") {
throw new Error("Invalid data");
}
state = result.state;
}
return new OAuth2RequestError(code, description, uri, state);
const error = new OAuth2RequestError(code, description, uri, state);
return error;
}

@@ -117,1 +172,17 @@ export class ArcticFetchError extends Error {

}
export class UnexpectedResponseError extends Error {
status;
constructor(responseStatus) {
super("Unexpected error response");
this.status = responseStatus;
}
}
export class UnexpectedErrorResponseBodyError extends Error {
status;
data;
constructor(status, data) {
super("Unexpected error response body");
this.status = status;
this.data = data;
}
}
{
"name": "arctic",
"type": "module",
"version": "2.3.3",
"description": "OAuth 2.0 clients for popular providers",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"module": "dist/index.js",
"files": [
"/dist/"
],
"author": "pilcrowOnPaper",
"license": "MIT",
"repository": {
"type": "git",
"url": "https://github.com/pilcrowOnPaper/arctic"
},
"devDependencies": {
"@types/node": "^20.8.6",
"@typescript-eslint/eslint-plugin": "^6.7.5",
"@typescript-eslint/parser": "^6.7.5",
"eslint": "^8.51.0",
"prettier": "^3.0.3",
"typescript": "^5.2.2",
"vitest": "1.6.0"
},
"dependencies": {
"@oslojs/crypto": "1.0.1",
"@oslojs/encoding": "1.1.0",
"@oslojs/jwt": "0.2.0"
},
"scripts": {
"build": "rm -rf dist/* && tsc",
"format": "prettier -w .",
"lint": "eslint src",
"test": "vitest run --sequence.concurrent"
}
}
"name": "arctic",
"type": "module",
"version": "3.0.0",
"description": "OAuth 2.0 clients for popular providers",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"module": "dist/index.js",
"scripts": {
"build": "rm -rf dist/* && tsc",
"format": "prettier -w .",
"lint": "eslint src",
"test": "vitest run --sequence.concurrent"
},
"files": [
"/dist/"
],
"author": "pilcrowOnPaper",
"license": "MIT",
"repository": {
"type": "git",
"url": "https://github.com/pilcrowonpaper/arctic.git"
},
"devDependencies": {
"@types/node": "^20.8.6",
"@typescript-eslint/eslint-plugin": "^6.7.5",
"@typescript-eslint/parser": "^6.7.5",
"auri": "^3.1.0",
"eslint": "^8.51.0",
"prettier": "^3.0.3",
"typescript": "^5.2.2",
"vitest": "1.6.0"
},
"dependencies": {
"@oslojs/crypto": "1.0.1",
"@oslojs/encoding": "1.1.0",
"@oslojs/jwt": "0.2.0"
}
}

@@ -5,3 +5,3 @@ # Arctic

Arctic is a collection of OAuth 2.0 clients for popular providers. It only supports the authorization code grant type and intended to be used server-side. Built on top of the Fetch API, it's light weight, fully-typed, and runtime-agnostic.
Arctic is a collection of OAuth 2.0 clients for popular providers. Only the authorization code flow is supported. Built on top of the Fetch API, it's light weight, fully-typed, and runtime-agnostic.

@@ -13,7 +13,7 @@ ```

```ts
import { GitHub, generateState } from "arctic";
import * as arctic from "arctic";
const github = new GitHub(clientId, clientSecret);
const github = new arctic.GitHub(clientId, clientSecret);
const state = generateState();
const state = arctic.generateState();
const scopes = ["user:email"];

@@ -79,2 +79,3 @@ const authorizationURL = github.createAuthorizationURL(state, scopes);

- Strava
- TikTok
- Tiltify

@@ -81,0 +82,0 @@ - Tumblr

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc