@workos-inc/authkit-js
Advanced tools
Comparing version 0.1.0 to 0.2.0
interface User { | ||
object: 'user'; | ||
object: "user"; | ||
id: string; | ||
@@ -44,2 +44,3 @@ email: string; | ||
invitationToken?: string; | ||
passwordResetToken?: string; | ||
} | ||
@@ -46,0 +47,0 @@ declare function createClient(clientId: string, options?: CreateClientOptions): Promise<{ |
@@ -53,3 +53,10 @@ "use strict"; | ||
var deserializeAuthenticationResponse = (authenticationResponse) => { | ||
const { user, organization_id, access_token, refresh_token, impersonator, ...rest } = authenticationResponse; | ||
const { | ||
user, | ||
organization_id, | ||
access_token, | ||
refresh_token, | ||
impersonator, | ||
...rest | ||
} = authenticationResponse; | ||
return { | ||
@@ -72,3 +79,3 @@ user: deserializeUser(user), | ||
headers: { | ||
"Accept": "application/json, text/plain, */*", | ||
Accept: "application/json, text/plain, */*", | ||
"Content-Type": "application/json" | ||
@@ -100,3 +107,3 @@ }, | ||
headers: { | ||
"Accept": "application/json, text/plain, */*", | ||
Accept: "application/json, text/plain, */*", | ||
"Content-Type": "application/json" | ||
@@ -143,2 +150,3 @@ }, | ||
screenHint, | ||
passwordResetToken, | ||
invitationToken, | ||
@@ -154,3 +162,5 @@ codeChallenge, | ||
if (provider !== "authkit" && screenHint) { | ||
throw new TypeError(`'screenHint' is only supported for 'authkit' provider`); | ||
throw new TypeError( | ||
`'screenHint' is only supported for 'authkit' provider` | ||
); | ||
} | ||
@@ -169,2 +179,3 @@ const query = toQueryString({ | ||
invitation_token: invitationToken, | ||
password_reset_token: passwordResetToken, | ||
code_challenge: codeChallenge, | ||
@@ -271,3 +282,5 @@ code_challenge_method: codeChallengeMethod | ||
function base64urlEncode(buffer) { | ||
return btoa(Array.from(new Uint8Array(buffer), (b) => String.fromCharCode(b)).join("")).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, ""); | ||
return btoa( | ||
Array.from(new Uint8Array(buffer), (b) => String.fromCharCode(b)).join("") | ||
).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, ""); | ||
} | ||
@@ -632,3 +645,8 @@ function sha256(plain) { | ||
} | ||
async function _redirect({ type, state, invitationToken }) { | ||
async function _redirect({ | ||
type, | ||
state, | ||
invitationToken, | ||
passwordResetToken | ||
}) { | ||
const { codeVerifier, codeChallenge } = await createPkceChallenge(); | ||
@@ -643,2 +661,3 @@ window.sessionStorage.setItem(storageKeys.codeVerifier, codeVerifier); | ||
invitationToken, | ||
passwordResetToken, | ||
state: state ? JSON.stringify(state) : void 0 | ||
@@ -645,0 +664,0 @@ }); |
{ | ||
"name": "@workos-inc/authkit-js", | ||
"version": "0.1.0", | ||
"version": "0.2.0", | ||
"description": "AuthKit SDK", | ||
@@ -16,2 +16,4 @@ "main": "./dist/index.js", | ||
"build": "tsup", | ||
"format": "prettier --write .", | ||
"format:check": "prettier --check .", | ||
"test": "echo \"Error: no test specified\" && exit 1" | ||
@@ -29,2 +31,3 @@ }, | ||
"devDependencies": { | ||
"prettier": "^3.3.3", | ||
"ts-node": "^10.9.2", | ||
@@ -31,0 +34,0 @@ "tsup": "^8.1.2", |
# AuthKit JavaScript Library | ||
This library can be used to interface with AuthKit in a client-side JavaScript | ||
application. | ||
application. | ||
@@ -6,0 +6,0 @@ ## Installation |
@@ -24,2 +24,3 @@ import { CreateClientOptions, User } from "./interfaces"; | ||
invitationToken?: string; | ||
passwordResetToken?: string; | ||
} | ||
@@ -33,3 +34,3 @@ | ||
clientId: string, | ||
options: CreateClientOptions = {} | ||
options: CreateClientOptions = {}, | ||
) { | ||
@@ -91,3 +92,8 @@ if (!clientId) { | ||
async function _redirect({ type, state, invitationToken }: RedirectOptions) { | ||
async function _redirect({ | ||
type, | ||
state, | ||
invitationToken, | ||
passwordResetToken, | ||
}: RedirectOptions) { | ||
const { codeVerifier, codeChallenge } = await createPkceChallenge(); | ||
@@ -103,2 +109,3 @@ // store the code verifier in session storage for later use (after the redirect back from authkit) | ||
invitationToken, | ||
passwordResetToken, | ||
state: state ? JSON.stringify(state) : undefined, | ||
@@ -170,3 +177,3 @@ }); | ||
const codeVerifier = window.sessionStorage.getItem( | ||
storageKeys.codeVerifier | ||
storageKeys.codeVerifier, | ||
); | ||
@@ -173,0 +180,0 @@ |
@@ -1,1 +0,1 @@ | ||
export { NoClientIdProvidedException } from './no-client-id-provided.exception'; | ||
export { NoClientIdProvidedException } from "./no-client-id-provided.exception"; |
export class NoClientIdProvidedException extends Error { | ||
readonly status: number = 500; | ||
readonly name: string = 'NoClientIdProvidedException'; | ||
readonly message: string = `Missing Client ID. Pass it to the constructor (createClient("client_01HXRMBQ9BJ3E7QSTQ9X2PHVB7"))`; | ||
readonly status: number = 500; | ||
readonly name: string = "NoClientIdProvidedException"; | ||
readonly message: string = `Missing Client ID. Pass it to the constructor (createClient("client_01HXRMBQ9BJ3E7QSTQ9X2PHVB7"))`; | ||
} |
@@ -1,3 +0,3 @@ | ||
export { createClient } from './create-client'; | ||
export { getClaims } from './utils/session-data'; | ||
export { User, AuthenticationResponse } from './interfaces'; | ||
export { createClient } from "./create-client"; | ||
export { getClaims } from "./utils/session-data"; | ||
export { User, AuthenticationResponse } from "./interfaces"; |
@@ -1,18 +0,18 @@ | ||
import { User, UserRaw } from './user.interface'; | ||
import { Impersonator, ImpersonatorRaw } from './impersonator.interface'; | ||
import { User, UserRaw } from "./user.interface"; | ||
import { Impersonator, ImpersonatorRaw } from "./impersonator.interface"; | ||
export interface AuthenticationResponse { | ||
user: User; | ||
accessToken: string; | ||
refreshToken: string; | ||
organizationId?: string; | ||
impersonator?: Impersonator; | ||
user: User; | ||
accessToken: string; | ||
refreshToken: string; | ||
organizationId?: string; | ||
impersonator?: Impersonator; | ||
} | ||
export interface AuthenticationResponseRaw { | ||
user: UserRaw; | ||
access_token: string; | ||
refresh_token: string; | ||
organization_id?: string; | ||
impersonator?: ImpersonatorRaw; | ||
user: UserRaw; | ||
access_token: string; | ||
refresh_token: string; | ||
organization_id?: string; | ||
impersonator?: ImpersonatorRaw; | ||
} |
export interface GetAuthorizationUrlOptions { | ||
clientId: string; | ||
connectionId?: string; | ||
organizationId?: string; | ||
domainHint?: string; | ||
loginHint?: string; | ||
provider?: string; | ||
redirectUri?: string; | ||
state?: string; | ||
screenHint?: 'sign-up' | 'sign-in'; | ||
clientId: string; | ||
connectionId?: string; | ||
organizationId?: string; | ||
domainHint?: string; | ||
loginHint?: string; | ||
provider?: string; | ||
redirectUri?: string; | ||
state?: string; | ||
screenHint?: "sign-up" | "sign-in"; | ||
invitationToken?: string; | ||
codeChallenge?: string; | ||
codeChallengeMethod?: string; | ||
passwordResetToken?: string; | ||
codeChallenge?: string; | ||
codeChallengeMethod?: string; | ||
} |
export interface Impersonator { | ||
email: string; | ||
reason: string | null; | ||
email: string; | ||
reason: string | null; | ||
} | ||
export interface ImpersonatorRaw { | ||
email: string; | ||
reason: string | null; | ||
email: string; | ||
reason: string | null; | ||
} |
@@ -1,5 +0,8 @@ | ||
export type { AuthenticationResponse, AuthenticationResponseRaw } from './authentication-response.interface'; | ||
export type { CreateClientOptions } from './create-client-options.interface'; | ||
export type { GetAuthorizationUrlOptions } from './get-authorization-url-options.interface'; | ||
export type { Impersonator, ImpersonatorRaw } from './impersonator.interface'; | ||
export type { User, UserRaw } from './user.interface'; | ||
export type { | ||
AuthenticationResponse, | ||
AuthenticationResponseRaw, | ||
} from "./authentication-response.interface"; | ||
export type { CreateClientOptions } from "./create-client-options.interface"; | ||
export type { GetAuthorizationUrlOptions } from "./get-authorization-url-options.interface"; | ||
export type { Impersonator, ImpersonatorRaw } from "./impersonator.interface"; | ||
export type { User, UserRaw } from "./user.interface"; |
export interface User { | ||
object: 'user'; | ||
id: string; | ||
email: string; | ||
emailVerified: boolean; | ||
profilePictureUrl: string | null; | ||
firstName: string | null; | ||
lastName: string | null; | ||
createdAt: string; | ||
updatedAt: string; | ||
object: "user"; | ||
id: string; | ||
email: string; | ||
emailVerified: boolean; | ||
profilePictureUrl: string | null; | ||
firstName: string | null; | ||
lastName: string | null; | ||
createdAt: string; | ||
updatedAt: string; | ||
} | ||
export interface UserRaw { | ||
object: 'user'; | ||
id: string; | ||
email: string; | ||
email_verified: boolean; | ||
profile_picture_url: string | null; | ||
first_name: string | null; | ||
last_name: string | null; | ||
created_at: string; | ||
updated_at: string; | ||
object: "user"; | ||
id: string; | ||
email: string; | ||
email_verified: boolean; | ||
profile_picture_url: string | null; | ||
first_name: string | null; | ||
last_name: string | null; | ||
created_at: string; | ||
updated_at: string; | ||
} |
@@ -1,17 +0,27 @@ | ||
import { AuthenticationResponse, AuthenticationResponseRaw } from '../interfaces'; | ||
import { deserializeUser } from './user.serializer'; | ||
import { | ||
AuthenticationResponse, | ||
AuthenticationResponseRaw, | ||
} from "../interfaces"; | ||
import { deserializeUser } from "./user.serializer"; | ||
export const deserializeAuthenticationResponse = ( | ||
authenticationResponse: AuthenticationResponseRaw, | ||
authenticationResponse: AuthenticationResponseRaw, | ||
): AuthenticationResponse => { | ||
const { user, organization_id, access_token, refresh_token, impersonator, ...rest } = authenticationResponse; | ||
const { | ||
user, | ||
organization_id, | ||
access_token, | ||
refresh_token, | ||
impersonator, | ||
...rest | ||
} = authenticationResponse; | ||
return { | ||
user: deserializeUser(user), | ||
organizationId: organization_id, | ||
accessToken: access_token, | ||
refreshToken: refresh_token, | ||
impersonator, | ||
...rest, | ||
}; | ||
return { | ||
user: deserializeUser(user), | ||
organizationId: organization_id, | ||
accessToken: access_token, | ||
refreshToken: refresh_token, | ||
impersonator, | ||
...rest, | ||
}; | ||
}; |
@@ -1,2 +0,2 @@ | ||
export { deserializeAuthenticationResponse } from './authentication-response.serializer'; | ||
export { deserializeUser } from './user.serializer'; | ||
export { deserializeAuthenticationResponse } from "./authentication-response.serializer"; | ||
export { deserializeUser } from "./user.serializer"; |
@@ -1,13 +0,13 @@ | ||
import { User, UserRaw } from '../interfaces'; | ||
import { User, UserRaw } from "../interfaces"; | ||
export const deserializeUser = (user: UserRaw): User => ({ | ||
object: user.object, | ||
id: user.id, | ||
email: user.email, | ||
emailVerified: user.email_verified, | ||
firstName: user.first_name, | ||
profilePictureUrl: user.profile_picture_url, | ||
lastName: user.last_name, | ||
createdAt: user.created_at, | ||
updatedAt: user.updated_at, | ||
object: user.object, | ||
id: user.id, | ||
email: user.email, | ||
emailVerified: user.email_verified, | ||
firstName: user.first_name, | ||
profilePictureUrl: user.profile_picture_url, | ||
lastName: user.last_name, | ||
createdAt: user.created_at, | ||
updatedAt: user.updated_at, | ||
}); |
@@ -1,3 +0,3 @@ | ||
import { AuthenticationResponseRaw } from '../interfaces'; | ||
import { deserializeAuthenticationResponse } from '../serializers'; | ||
import { AuthenticationResponseRaw } from "../interfaces"; | ||
import { deserializeAuthenticationResponse } from "../serializers"; | ||
@@ -12,10 +12,12 @@ interface AuthenticateWithCodeOptions { | ||
export async function authenticateWithCode(options: AuthenticateWithCodeOptions) { | ||
export async function authenticateWithCode( | ||
options: AuthenticateWithCodeOptions, | ||
) { | ||
const { baseUrl, clientId, code, codeVerifier, useCookie } = options; | ||
const response = await fetch(`${baseUrl}/user_management/authenticate`, { | ||
method: 'POST', | ||
...(useCookie && { credentials: 'include' }), | ||
method: "POST", | ||
...(useCookie && { credentials: "include" }), | ||
headers: { | ||
'Accept': 'application/json, text/plain, */*', | ||
'Content-Type': 'application/json', | ||
Accept: "application/json, text/plain, */*", | ||
"Content-Type": "application/json", | ||
}, | ||
@@ -25,3 +27,3 @@ body: JSON.stringify({ | ||
client_id: clientId, | ||
grant_type: 'authorization_code', | ||
grant_type: "authorization_code", | ||
code_verifier: codeVerifier, | ||
@@ -35,4 +37,4 @@ }), | ||
} else { | ||
console.log('error', await response.json()); | ||
console.log("error", await response.json()); | ||
} | ||
} |
@@ -1,3 +0,3 @@ | ||
import { AuthenticationResponseRaw } from '../interfaces'; | ||
import { deserializeAuthenticationResponse } from '../serializers'; | ||
import { AuthenticationResponseRaw } from "../interfaces"; | ||
import { deserializeAuthenticationResponse } from "../serializers"; | ||
@@ -13,14 +13,16 @@ interface AuthenticateWithRefreshTokenOptions { | ||
export async function authenticateWithRefreshToken(options: AuthenticateWithRefreshTokenOptions) { | ||
export async function authenticateWithRefreshToken( | ||
options: AuthenticateWithRefreshTokenOptions, | ||
) { | ||
const { baseUrl, clientId, refreshToken, useCookie } = options; | ||
const response = await fetch(`${baseUrl}/user_management/authenticate`, { | ||
method: 'POST', | ||
...(useCookie && { credentials: 'include' }), | ||
method: "POST", | ||
...(useCookie && { credentials: "include" }), | ||
headers: { | ||
'Accept': 'application/json, text/plain, */*', | ||
'Content-Type': 'application/json', | ||
Accept: "application/json, text/plain, */*", | ||
"Content-Type": "application/json", | ||
}, | ||
body: JSON.stringify({ | ||
client_id: clientId, | ||
grant_type: 'refresh_token', | ||
grant_type: "refresh_token", | ||
...(!useCookie && { refresh_token: refreshToken }), | ||
@@ -34,5 +36,5 @@ }), | ||
} else { | ||
const error = await response.json() as any; | ||
const error = (await response.json()) as any; | ||
throw new RefreshError(error.error_description); | ||
} | ||
} |
@@ -1,48 +0,52 @@ | ||
import { GetAuthorizationUrlOptions } from '../interfaces'; | ||
import { toQueryString } from './to-query-string'; | ||
import { GetAuthorizationUrlOptions } from "../interfaces"; | ||
import { toQueryString } from "./to-query-string"; | ||
export function getAuthorizationUrl( | ||
baseUrl: string, | ||
{ | ||
clientId, | ||
connectionId, | ||
domainHint, | ||
loginHint, | ||
organizationId, | ||
provider = 'authkit', | ||
redirectUri, | ||
state, | ||
screenHint, | ||
baseUrl: string, | ||
{ | ||
clientId, | ||
connectionId, | ||
domainHint, | ||
loginHint, | ||
organizationId, | ||
provider = "authkit", | ||
redirectUri, | ||
state, | ||
screenHint, | ||
passwordResetToken, | ||
invitationToken, | ||
codeChallenge, | ||
codeChallengeMethod, | ||
}: GetAuthorizationUrlOptions, | ||
codeChallenge, | ||
codeChallengeMethod, | ||
}: GetAuthorizationUrlOptions, | ||
): string { | ||
if (!provider && !connectionId && !organizationId) { | ||
throw new TypeError( | ||
`Incomplete arguments. Need to specify either a 'connectionId', 'organizationId', or 'provider'.`, | ||
); | ||
} | ||
if (!provider && !connectionId && !organizationId) { | ||
throw new TypeError( | ||
`Incomplete arguments. Need to specify either a 'connectionId', 'organizationId', or 'provider'.`, | ||
); | ||
} | ||
if (provider !== 'authkit' && screenHint) { | ||
throw new TypeError(`'screenHint' is only supported for 'authkit' provider`); | ||
} | ||
if (provider !== "authkit" && screenHint) { | ||
throw new TypeError( | ||
`'screenHint' is only supported for 'authkit' provider`, | ||
); | ||
} | ||
const query = toQueryString({ | ||
connection_id: connectionId, | ||
organization_id: organizationId, | ||
domain_hint: domainHint, | ||
login_hint: loginHint, | ||
provider, | ||
client_id: clientId, | ||
redirect_uri: redirectUri, | ||
response_type: 'code', | ||
state, | ||
screen_hint: screenHint, | ||
const query = toQueryString({ | ||
connection_id: connectionId, | ||
organization_id: organizationId, | ||
domain_hint: domainHint, | ||
login_hint: loginHint, | ||
provider, | ||
client_id: clientId, | ||
redirect_uri: redirectUri, | ||
response_type: "code", | ||
state, | ||
screen_hint: screenHint, | ||
invitation_token: invitationToken, | ||
code_challenge: codeChallenge, | ||
code_challenge_method: codeChallengeMethod, | ||
}); | ||
password_reset_token: passwordResetToken, | ||
code_challenge: codeChallenge, | ||
code_challenge_method: codeChallengeMethod, | ||
}); | ||
return `${baseUrl}/user_management/authorize?${query}`; | ||
return `${baseUrl}/user_management/authorize?${query}`; | ||
} |
@@ -1,10 +0,10 @@ | ||
export { authenticateWithCode } from './authenticate-with-code'; | ||
export { authenticateWithRefreshToken } from './authenticate-with-refresh-token'; | ||
export { getAuthorizationUrl } from './get-authorization-url'; | ||
export { getLogoutUrl } from './get-logout-url'; | ||
export { isRedirectCallback } from './is-redirect-callback'; | ||
export { memoryStorage } from './memory-storage'; | ||
export { createPkceChallenge } from './pkce'; | ||
export { setSessionData, removeSessionData } from './session-data'; | ||
export { storageKeys } from './storage-keys'; | ||
export { toQueryString } from './to-query-string'; | ||
export { authenticateWithCode } from "./authenticate-with-code"; | ||
export { authenticateWithRefreshToken } from "./authenticate-with-refresh-token"; | ||
export { getAuthorizationUrl } from "./get-authorization-url"; | ||
export { getLogoutUrl } from "./get-logout-url"; | ||
export { isRedirectCallback } from "./is-redirect-callback"; | ||
export { memoryStorage } from "./memory-storage"; | ||
export { createPkceChallenge } from "./pkce"; | ||
export { setSessionData, removeSessionData } from "./session-data"; | ||
export { storageKeys } from "./storage-keys"; | ||
export { toQueryString } from "./to-query-string"; |
@@ -1,3 +0,6 @@ | ||
export function isRedirectCallback(redirectUri: string, searchParams: URLSearchParams) { | ||
const hasCode = searchParams.has('code'); | ||
export function isRedirectCallback( | ||
redirectUri: string, | ||
searchParams: URLSearchParams, | ||
) { | ||
const hasCode = searchParams.has("code"); | ||
if (!hasCode) return false; | ||
@@ -4,0 +7,0 @@ |
function createMemoryStorage() { | ||
let _store: { [key: string]: unknown } = {}; | ||
let _store: { [key: string]: unknown } = {}; | ||
function setItem(key: string, value: unknown): void { | ||
_store[key] = value; | ||
} | ||
function setItem(key: string, value: unknown): void { | ||
_store[key] = value; | ||
} | ||
function getItem(key: string): unknown { | ||
return _store[key]; | ||
} | ||
function getItem(key: string): unknown { | ||
return _store[key]; | ||
} | ||
function removeItem(key: string): void { | ||
delete _store[key]; | ||
} | ||
function removeItem(key: string): void { | ||
delete _store[key]; | ||
} | ||
function reset(): void { | ||
_store = {}; | ||
} | ||
function reset(): void { | ||
_store = {}; | ||
} | ||
return { | ||
setItem, | ||
getItem, | ||
removeItem, | ||
reset, | ||
}; | ||
return { | ||
setItem, | ||
getItem, | ||
removeItem, | ||
reset, | ||
}; | ||
} | ||
@@ -27,0 +27,0 @@ |
export async function createPkceChallenge() { | ||
const codeVerifier = createCodeVerifier(); | ||
const codeChallenge = await createCodeChallenge(codeVerifier); | ||
const codeVerifier = createCodeVerifier(); | ||
const codeChallenge = await createCodeChallenge(codeVerifier); | ||
return { codeVerifier, codeChallenge }; | ||
return { codeVerifier, codeChallenge }; | ||
} | ||
function createCodeVerifier() { | ||
const randomBytes = crypto.getRandomValues(new Uint32Array(96)); | ||
return base64urlEncode(randomBytes); | ||
const randomBytes = crypto.getRandomValues(new Uint32Array(96)); | ||
return base64urlEncode(randomBytes); | ||
} | ||
async function createCodeChallenge(codeVerifier: string) { | ||
const hashed = await sha256(codeVerifier); | ||
return base64urlEncode(hashed); | ||
const hashed = await sha256(codeVerifier); | ||
return base64urlEncode(hashed); | ||
} | ||
function base64urlEncode(buffer: ArrayBuffer): string { | ||
return btoa(Array.from(new Uint8Array(buffer), (b) => String.fromCharCode(b)).join('')) | ||
.replace(/\+/g, '-') | ||
.replace(/\//g, '_') | ||
.replace(/=+$/, ''); | ||
return btoa( | ||
Array.from(new Uint8Array(buffer), (b) => String.fromCharCode(b)).join(""), | ||
) | ||
.replace(/\+/g, "-") | ||
.replace(/\//g, "_") | ||
.replace(/=+$/, ""); | ||
} | ||
function sha256(plain: string): Promise<ArrayBuffer> { | ||
const encoder = new TextEncoder(); | ||
const data = encoder.encode(plain); | ||
return window.crypto.subtle.digest('SHA-256', data); | ||
const encoder = new TextEncoder(); | ||
const data = encoder.encode(plain); | ||
return window.crypto.subtle.digest("SHA-256", data); | ||
} |
@@ -24,3 +24,3 @@ import { AuthenticationResponse } from "../interfaces"; | ||
data: AuthenticationResponse, | ||
{ devMode = false } = {} | ||
{ devMode = false } = {}, | ||
) { | ||
@@ -32,7 +32,7 @@ const { user, accessToken, refreshToken } = data; | ||
storageKeys.refreshToken, | ||
refreshToken | ||
refreshToken, | ||
); | ||
// compute a local time version of expires at (should avoid issues with slightly-wrong clocks) | ||
const {exp, iat} = getClaims(accessToken); | ||
const { exp, iat } = getClaims(accessToken); | ||
const expiresIn = exp - iat; | ||
@@ -47,3 +47,3 @@ const expiresAt = Date.now() + expiresIn * 1000; | ||
(devMode ? window.localStorage : memoryStorage).removeItem( | ||
storageKeys.refreshToken | ||
storageKeys.refreshToken, | ||
); | ||
@@ -54,4 +54,4 @@ } | ||
return (devMode ? window.localStorage : memoryStorage).getItem( | ||
storageKeys.refreshToken | ||
storageKeys.refreshToken, | ||
) as string | undefined; | ||
} |
export const storageKeys = { | ||
codeVerifier: 'workos:code-verifier', | ||
user: 'workos:user', | ||
accessToken: 'workos:access-token', | ||
refreshToken: 'workos:refresh-token', | ||
expiresAt: 'workos:expires-at', | ||
codeVerifier: "workos:code-verifier", | ||
user: "workos:user", | ||
accessToken: "workos:access-token", | ||
refreshToken: "workos:refresh-token", | ||
expiresAt: "workos:expires-at", | ||
} as const; |
@@ -1,14 +0,16 @@ | ||
export function toQueryString(options: Record<string, string | undefined>): string { | ||
const searchParams = new URLSearchParams(); | ||
const keys = Object.keys(options).sort(); | ||
export function toQueryString( | ||
options: Record<string, string | undefined>, | ||
): string { | ||
const searchParams = new URLSearchParams(); | ||
const keys = Object.keys(options).sort(); | ||
for (const key of keys) { | ||
const value = options[key]; | ||
for (const key of keys) { | ||
const value = options[key]; | ||
if (value) { | ||
searchParams.append(key, value); | ||
} | ||
} | ||
if (value) { | ||
searchParams.append(key, value); | ||
} | ||
} | ||
return searchParams.toString(); | ||
return searchParams.toString(); | ||
} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
184062
2570
4
4