@supabase/gotrue-js
Advanced tools
Comparing version 2.68.1-rc.1 to 2.69.0-rc.2
@@ -5,3 +5,3 @@ import GoTrueAdminApi from './GoTrueAdminApi'; | ||
import { Deferred } from './lib/helpers'; | ||
import type { AuthChangeEvent, AuthResponse, AuthTokenResponse, AuthTokenResponsePassword, AuthOtpResponse, CallRefreshTokenResult, GoTrueClientOptions, InitializeResult, OAuthResponse, SSOResponse, Session, SignInWithIdTokenCredentials, SignInWithOAuthCredentials, SignInWithPasswordCredentials, SignInWithPasswordlessCredentials, SignUpWithPasswordCredentials, SignInWithSSO, SignOut, Subscription, SupportedStorage, UserAttributes, UserResponse, VerifyOtpParams, GoTrueMFAApi, ResendParams, AuthFlowType, LockFunc, UserIdentity, SignInAnonymouslyCredentials } from './lib/types'; | ||
import type { AuthChangeEvent, AuthResponse, AuthTokenResponse, AuthTokenResponsePassword, AuthOtpResponse, CallRefreshTokenResult, GoTrueClientOptions, InitializeResult, OAuthResponse, SSOResponse, Session, SignInWithIdTokenCredentials, SignInWithOAuthCredentials, SignInWithPasswordCredentials, SignInWithPasswordlessCredentials, SignUpWithPasswordCredentials, SignInWithSSO, SignOut, Subscription, SupportedStorage, UserAttributes, UserResponse, VerifyOtpParams, GoTrueMFAApi, ResendParams, AuthFlowType, LockFunc, UserIdentity, SignInAnonymouslyCredentials, JWK, JwtPayload, JwtHeader } from './lib/types'; | ||
export default class GoTrueClient { | ||
@@ -24,2 +24,8 @@ private static nextInstanceID; | ||
protected flowType: AuthFlowType; | ||
/** | ||
* The JWKS used for verifying asymmetric JWTs | ||
*/ | ||
protected jwks: { | ||
keys: JWK[]; | ||
}; | ||
protected autoRefreshToken: boolean; | ||
@@ -228,6 +234,2 @@ protected persistSession: boolean; | ||
/** | ||
* Decodes a JWT (without performing any validation). | ||
*/ | ||
private _decodeJWT; | ||
/** | ||
* Sets the session data from the current session. If the current session is expired, setSession will take care of refreshing it to obtain a new session. | ||
@@ -452,3 +454,24 @@ * If the refresh token or access token in the current session is invalid, an error will be thrown. | ||
private _getAuthenticatorAssuranceLevel; | ||
private fetchJwk; | ||
/** | ||
* @experimental This method may change in future versions. | ||
* @description Gets the claims from a JWT. If the JWT is symmetric JWTs, it will call getUser() to verify against the server. If the JWT is asymmetric, it will be verified against the JWKS using the WebCrypto API. | ||
*/ | ||
getClaims(jwt?: string, jwks?: { | ||
keys: JWK[]; | ||
}): Promise<{ | ||
data: { | ||
claims: JwtPayload; | ||
header: JwtHeader; | ||
signature: Uint8Array; | ||
}; | ||
error: null; | ||
} | { | ||
data: null; | ||
error: AuthError; | ||
} | { | ||
data: null; | ||
error: null; | ||
}>; | ||
} | ||
//# sourceMappingURL=GoTrueClient.d.ts.map |
@@ -24,2 +24,3 @@ /** Current session will be checked for refresh at this interval. */ | ||
}; | ||
export declare const BASE64URL_REGEX: RegExp; | ||
//# sourceMappingURL=constants.d.ts.map |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.API_VERSIONS = exports.API_VERSION_HEADER_NAME = exports.NETWORK_FAILURE = exports.DEFAULT_HEADERS = exports.AUDIENCE = exports.STORAGE_KEY = exports.GOTRUE_URL = exports.EXPIRY_MARGIN_MS = exports.AUTO_REFRESH_TICK_THRESHOLD = exports.AUTO_REFRESH_TICK_DURATION_MS = void 0; | ||
exports.BASE64URL_REGEX = exports.API_VERSIONS = exports.API_VERSION_HEADER_NAME = exports.NETWORK_FAILURE = exports.DEFAULT_HEADERS = exports.AUDIENCE = exports.STORAGE_KEY = exports.GOTRUE_URL = exports.EXPIRY_MARGIN_MS = exports.AUTO_REFRESH_TICK_THRESHOLD = exports.AUTO_REFRESH_TICK_DURATION_MS = void 0; | ||
const version_1 = require("./version"); | ||
@@ -29,2 +29,3 @@ /** Current session will be checked for refresh at this interval. */ | ||
}; | ||
exports.BASE64URL_REGEX = /^([a-z0-9_-]{4})*($|[a-z0-9_-]{3}$|[a-z0-9_-]{2}$)$/i; | ||
//# sourceMappingURL=constants.js.map |
@@ -97,2 +97,5 @@ import { WeakPasswordReasons } from './types'; | ||
export declare function isAuthWeakPasswordError(error: unknown): error is AuthWeakPasswordError; | ||
export declare class AuthInvalidJwtError extends CustomAuthError { | ||
constructor(message: string); | ||
} | ||
//# sourceMappingURL=errors.d.ts.map |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.isAuthWeakPasswordError = exports.AuthWeakPasswordError = exports.isAuthRetryableFetchError = exports.AuthRetryableFetchError = exports.AuthPKCEGrantCodeExchangeError = exports.isAuthImplicitGrantRedirectError = exports.AuthImplicitGrantRedirectError = exports.AuthInvalidCredentialsError = exports.AuthInvalidTokenResponseError = exports.isAuthSessionMissingError = exports.AuthSessionMissingError = exports.CustomAuthError = exports.AuthUnknownError = exports.isAuthApiError = exports.AuthApiError = exports.isAuthError = exports.AuthError = void 0; | ||
exports.AuthInvalidJwtError = exports.isAuthWeakPasswordError = exports.AuthWeakPasswordError = exports.isAuthRetryableFetchError = exports.AuthRetryableFetchError = exports.AuthPKCEGrantCodeExchangeError = exports.isAuthImplicitGrantRedirectError = exports.AuthImplicitGrantRedirectError = exports.AuthInvalidCredentialsError = exports.AuthInvalidTokenResponseError = exports.isAuthSessionMissingError = exports.AuthSessionMissingError = exports.CustomAuthError = exports.AuthUnknownError = exports.isAuthApiError = exports.AuthApiError = exports.isAuthError = exports.AuthError = void 0; | ||
class AuthError extends Error { | ||
@@ -131,2 +131,8 @@ constructor(message, status, code) { | ||
exports.isAuthWeakPasswordError = isAuthWeakPasswordError; | ||
class AuthInvalidJwtError extends CustomAuthError { | ||
constructor(message) { | ||
super(message, 'AuthInvalidJwtError', 400, 'invalid_jwt'); | ||
} | ||
} | ||
exports.AuthInvalidJwtError = AuthInvalidJwtError; | ||
//# sourceMappingURL=errors.js.map |
@@ -1,2 +0,2 @@ | ||
import { SupportedStorage } from './types'; | ||
import { JwtHeader, JwtPayload, SupportedStorage } from './types'; | ||
export declare function expiresAt(expiresIn: number): number; | ||
@@ -21,3 +21,2 @@ export declare function uuid(): string; | ||
export declare const removeItemAsync: (storage: SupportedStorage, key: string) => Promise<void>; | ||
export declare function decodeBase64URL(value: string): string; | ||
/** | ||
@@ -35,3 +34,11 @@ * A deferred represents some asynchronous work that is not yet finished, which | ||
} | ||
export declare function decodeJWTPayload(token: string): any; | ||
export declare function decodeJWT(token: string): { | ||
header: JwtHeader; | ||
payload: JwtPayload; | ||
signature: Uint8Array; | ||
raw: { | ||
header: string; | ||
payload: string; | ||
}; | ||
}; | ||
/** | ||
@@ -51,3 +58,5 @@ * Creates a promise that resolves to null after some time. | ||
export declare function parseResponseAPIVersion(response: Response): Date | null; | ||
export declare function validateExp(exp: number): void; | ||
export declare function getAlgorithm(alg: 'RS256' | 'ES256'): RsaHashedImportParams | EcKeyImportParams; | ||
export {}; | ||
//# sourceMappingURL=helpers.d.ts.map |
@@ -26,4 +26,6 @@ "use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.parseResponseAPIVersion = exports.getCodeChallengeAndMethod = exports.generatePKCEChallenge = exports.generatePKCEVerifier = exports.retryable = exports.sleep = exports.decodeJWTPayload = exports.Deferred = exports.decodeBase64URL = exports.removeItemAsync = exports.getItemAsync = exports.setItemAsync = exports.looksLikeFetchResponse = exports.resolveFetch = exports.parseParametersFromURL = exports.supportsLocalStorage = exports.isBrowser = exports.uuid = exports.expiresAt = void 0; | ||
exports.getAlgorithm = exports.validateExp = exports.parseResponseAPIVersion = exports.getCodeChallengeAndMethod = exports.generatePKCEChallenge = exports.generatePKCEVerifier = exports.retryable = exports.sleep = exports.decodeJWT = exports.Deferred = exports.removeItemAsync = exports.getItemAsync = exports.setItemAsync = exports.looksLikeFetchResponse = exports.resolveFetch = exports.parseParametersFromURL = exports.supportsLocalStorage = exports.isBrowser = exports.uuid = exports.expiresAt = void 0; | ||
const constants_1 = require("./constants"); | ||
const errors_1 = require("./errors"); | ||
const base64url_1 = require("./base64url"); | ||
function expiresAt(expiresIn) { | ||
@@ -151,28 +153,2 @@ const timeNow = Math.round(Date.now() / 1000); | ||
exports.removeItemAsync = removeItemAsync; | ||
function decodeBase64URL(value) { | ||
const key = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='; | ||
let base64 = ''; | ||
let chr1, chr2, chr3; | ||
let enc1, enc2, enc3, enc4; | ||
let i = 0; | ||
value = value.replace('-', '+').replace('_', '/'); | ||
while (i < value.length) { | ||
enc1 = key.indexOf(value.charAt(i++)); | ||
enc2 = key.indexOf(value.charAt(i++)); | ||
enc3 = key.indexOf(value.charAt(i++)); | ||
enc4 = key.indexOf(value.charAt(i++)); | ||
chr1 = (enc1 << 2) | (enc2 >> 4); | ||
chr2 = ((enc2 & 15) << 4) | (enc3 >> 2); | ||
chr3 = ((enc3 & 3) << 6) | enc4; | ||
base64 = base64 + String.fromCharCode(chr1); | ||
if (enc3 != 64 && chr2 != 0) { | ||
base64 = base64 + String.fromCharCode(chr2); | ||
} | ||
if (enc4 != 64 && chr3 != 0) { | ||
base64 = base64 + String.fromCharCode(chr3); | ||
} | ||
} | ||
return base64; | ||
} | ||
exports.decodeBase64URL = decodeBase64URL; | ||
/** | ||
@@ -197,17 +173,26 @@ * A deferred represents some asynchronous work that is not yet finished, which | ||
Deferred.promiseConstructor = Promise; | ||
// Taken from: https://stackoverflow.com/questions/38552003/how-to-decode-jwt-token-in-javascript-without-using-a-library | ||
function decodeJWTPayload(token) { | ||
// Regex checks for base64url format | ||
const base64UrlRegex = /^([a-z0-9_-]{4})*($|[a-z0-9_-]{3}=?$|[a-z0-9_-]{2}(==)?$)$/i; | ||
function decodeJWT(token) { | ||
const parts = token.split('.'); | ||
if (parts.length !== 3) { | ||
throw new Error('JWT is not valid: not a JWT structure'); | ||
throw new errors_1.AuthInvalidJwtError('Invalid JWT structure'); | ||
} | ||
if (!base64UrlRegex.test(parts[1])) { | ||
throw new Error('JWT is not valid: payload is not in base64url format'); | ||
// Regex checks for base64url format | ||
for (let i = 0; i < parts.length; i++) { | ||
if (!constants_1.BASE64URL_REGEX.test(parts[i])) { | ||
throw new errors_1.AuthInvalidJwtError('JWT not in base64url format'); | ||
} | ||
} | ||
const base64Url = parts[1]; | ||
return JSON.parse(decodeBase64URL(base64Url)); | ||
const data = { | ||
// using base64url lib | ||
header: JSON.parse((0, base64url_1.stringFromBase64URL)(parts[0])), | ||
payload: JSON.parse((0, base64url_1.stringFromBase64URL)(parts[1])), | ||
signature: (0, base64url_1.base64UrlToUint8Array)(parts[2]), | ||
raw: { | ||
header: parts[0], | ||
payload: parts[1], | ||
}, | ||
}; | ||
return data; | ||
} | ||
exports.decodeJWTPayload = decodeJWTPayload; | ||
exports.decodeJWT = decodeJWT; | ||
/** | ||
@@ -281,5 +266,2 @@ * Creates a promise that resolves to null after some time. | ||
} | ||
function base64urlencode(str) { | ||
return btoa(str).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, ''); | ||
} | ||
async function generatePKCEChallenge(verifier) { | ||
@@ -294,3 +276,3 @@ const hasCryptoSupport = typeof crypto !== 'undefined' && | ||
const hashed = await sha256(verifier); | ||
return base64urlencode(hashed); | ||
return (0, base64url_1.stringToBase64URL)(hashed); | ||
} | ||
@@ -329,2 +311,30 @@ exports.generatePKCEChallenge = generatePKCEChallenge; | ||
exports.parseResponseAPIVersion = parseResponseAPIVersion; | ||
function validateExp(exp) { | ||
if (!exp) { | ||
throw new Error('Missing exp claim'); | ||
} | ||
const timeNow = Math.floor(Date.now() / 1000); | ||
if (exp <= timeNow) { | ||
throw new Error('JWT has expired'); | ||
} | ||
} | ||
exports.validateExp = validateExp; | ||
function getAlgorithm(alg) { | ||
switch (alg) { | ||
case 'RS256': | ||
return { | ||
name: 'RSASSA-PKCS1-v1_5', | ||
hash: { name: 'SHA-256' }, | ||
}; | ||
case 'ES256': | ||
return { | ||
name: 'ECDSA', | ||
namedCurve: 'P-256', | ||
hash: { name: 'SHA-256' }, | ||
}; | ||
default: | ||
throw new Error('Invalid alg claim'); | ||
} | ||
} | ||
exports.getAlgorithm = getAlgorithm; | ||
//# sourceMappingURL=helpers.js.map |
@@ -1014,3 +1014,28 @@ import { AuthError } from './errors'; | ||
}; | ||
export declare type JwtHeader = { | ||
alg: 'RS256' | 'ES256' | 'HS256'; | ||
kid: string; | ||
typ: string; | ||
}; | ||
export declare type RequiredClaims = { | ||
iss: string; | ||
sub: string; | ||
aud: string | string[]; | ||
exp: number; | ||
iat: number; | ||
role: string; | ||
aal: AuthenticatorAssuranceLevels; | ||
session_id: string; | ||
}; | ||
export declare type JwtPayload = RequiredClaims & { | ||
[key: string]: any; | ||
}; | ||
export interface JWK { | ||
kty: 'RSA' | 'EC' | 'oct'; | ||
key_ops: string[]; | ||
alg?: string; | ||
kid?: string; | ||
[key: string]: any; | ||
} | ||
export {}; | ||
//# sourceMappingURL=types.d.ts.map |
@@ -1,2 +0,2 @@ | ||
export declare const version = "2.68.1-rc.1"; | ||
export declare const version = "2.69.0-rc.2"; | ||
//# sourceMappingURL=version.d.ts.map |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.version = void 0; | ||
exports.version = '2.68.1-rc.1'; | ||
exports.version = '2.69.0-rc.2'; | ||
//# sourceMappingURL=version.js.map |
@@ -5,3 +5,3 @@ import GoTrueAdminApi from './GoTrueAdminApi'; | ||
import { Deferred } from './lib/helpers'; | ||
import type { AuthChangeEvent, AuthResponse, AuthTokenResponse, AuthTokenResponsePassword, AuthOtpResponse, CallRefreshTokenResult, GoTrueClientOptions, InitializeResult, OAuthResponse, SSOResponse, Session, SignInWithIdTokenCredentials, SignInWithOAuthCredentials, SignInWithPasswordCredentials, SignInWithPasswordlessCredentials, SignUpWithPasswordCredentials, SignInWithSSO, SignOut, Subscription, SupportedStorage, UserAttributes, UserResponse, VerifyOtpParams, GoTrueMFAApi, ResendParams, AuthFlowType, LockFunc, UserIdentity, SignInAnonymouslyCredentials } from './lib/types'; | ||
import type { AuthChangeEvent, AuthResponse, AuthTokenResponse, AuthTokenResponsePassword, AuthOtpResponse, CallRefreshTokenResult, GoTrueClientOptions, InitializeResult, OAuthResponse, SSOResponse, Session, SignInWithIdTokenCredentials, SignInWithOAuthCredentials, SignInWithPasswordCredentials, SignInWithPasswordlessCredentials, SignUpWithPasswordCredentials, SignInWithSSO, SignOut, Subscription, SupportedStorage, UserAttributes, UserResponse, VerifyOtpParams, GoTrueMFAApi, ResendParams, AuthFlowType, LockFunc, UserIdentity, SignInAnonymouslyCredentials, JWK, JwtPayload, JwtHeader } from './lib/types'; | ||
export default class GoTrueClient { | ||
@@ -24,2 +24,8 @@ private static nextInstanceID; | ||
protected flowType: AuthFlowType; | ||
/** | ||
* The JWKS used for verifying asymmetric JWTs | ||
*/ | ||
protected jwks: { | ||
keys: JWK[]; | ||
}; | ||
protected autoRefreshToken: boolean; | ||
@@ -228,6 +234,2 @@ protected persistSession: boolean; | ||
/** | ||
* Decodes a JWT (without performing any validation). | ||
*/ | ||
private _decodeJWT; | ||
/** | ||
* Sets the session data from the current session. If the current session is expired, setSession will take care of refreshing it to obtain a new session. | ||
@@ -452,3 +454,24 @@ * If the refresh token or access token in the current session is invalid, an error will be thrown. | ||
private _getAuthenticatorAssuranceLevel; | ||
private fetchJwk; | ||
/** | ||
* @experimental This method may change in future versions. | ||
* @description Gets the claims from a JWT. If the JWT is symmetric JWTs, it will call getUser() to verify against the server. If the JWT is asymmetric, it will be verified against the JWKS using the WebCrypto API. | ||
*/ | ||
getClaims(jwt?: string, jwks?: { | ||
keys: JWK[]; | ||
}): Promise<{ | ||
data: { | ||
claims: JwtPayload; | ||
header: JwtHeader; | ||
signature: Uint8Array; | ||
}; | ||
error: null; | ||
} | { | ||
data: null; | ||
error: AuthError; | ||
} | { | ||
data: null; | ||
error: null; | ||
}>; | ||
} | ||
//# sourceMappingURL=GoTrueClient.d.ts.map |
@@ -24,2 +24,3 @@ /** Current session will be checked for refresh at this interval. */ | ||
}; | ||
export declare const BASE64URL_REGEX: RegExp; | ||
//# sourceMappingURL=constants.d.ts.map |
@@ -26,2 +26,3 @@ import { version } from './version'; | ||
}; | ||
export const BASE64URL_REGEX = /^([a-z0-9_-]{4})*($|[a-z0-9_-]{3}$|[a-z0-9_-]{2}$)$/i; | ||
//# sourceMappingURL=constants.js.map |
@@ -97,2 +97,5 @@ import { WeakPasswordReasons } from './types'; | ||
export declare function isAuthWeakPasswordError(error: unknown): error is AuthWeakPasswordError; | ||
export declare class AuthInvalidJwtError extends CustomAuthError { | ||
constructor(message: string); | ||
} | ||
//# sourceMappingURL=errors.d.ts.map |
@@ -111,2 +111,7 @@ export class AuthError extends Error { | ||
} | ||
export class AuthInvalidJwtError extends CustomAuthError { | ||
constructor(message) { | ||
super(message, 'AuthInvalidJwtError', 400, 'invalid_jwt'); | ||
} | ||
} | ||
//# sourceMappingURL=errors.js.map |
@@ -1,2 +0,2 @@ | ||
import { SupportedStorage } from './types'; | ||
import { JwtHeader, JwtPayload, SupportedStorage } from './types'; | ||
export declare function expiresAt(expiresIn: number): number; | ||
@@ -21,3 +21,2 @@ export declare function uuid(): string; | ||
export declare const removeItemAsync: (storage: SupportedStorage, key: string) => Promise<void>; | ||
export declare function decodeBase64URL(value: string): string; | ||
/** | ||
@@ -35,3 +34,11 @@ * A deferred represents some asynchronous work that is not yet finished, which | ||
} | ||
export declare function decodeJWTPayload(token: string): any; | ||
export declare function decodeJWT(token: string): { | ||
header: JwtHeader; | ||
payload: JwtPayload; | ||
signature: Uint8Array; | ||
raw: { | ||
header: string; | ||
payload: string; | ||
}; | ||
}; | ||
/** | ||
@@ -51,3 +58,5 @@ * Creates a promise that resolves to null after some time. | ||
export declare function parseResponseAPIVersion(response: Response): Date | null; | ||
export declare function validateExp(exp: number): void; | ||
export declare function getAlgorithm(alg: 'RS256' | 'ES256'): RsaHashedImportParams | EcKeyImportParams; | ||
export {}; | ||
//# sourceMappingURL=helpers.d.ts.map |
@@ -1,2 +0,4 @@ | ||
import { API_VERSION_HEADER_NAME } from './constants'; | ||
import { API_VERSION_HEADER_NAME, BASE64URL_REGEX } from './constants'; | ||
import { AuthInvalidJwtError } from './errors'; | ||
import { base64UrlToUint8Array, stringFromBase64URL, stringToBase64URL } from './base64url'; | ||
export function expiresAt(expiresIn) { | ||
@@ -114,27 +116,2 @@ const timeNow = Math.round(Date.now() / 1000); | ||
}; | ||
export function decodeBase64URL(value) { | ||
const key = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='; | ||
let base64 = ''; | ||
let chr1, chr2, chr3; | ||
let enc1, enc2, enc3, enc4; | ||
let i = 0; | ||
value = value.replace('-', '+').replace('_', '/'); | ||
while (i < value.length) { | ||
enc1 = key.indexOf(value.charAt(i++)); | ||
enc2 = key.indexOf(value.charAt(i++)); | ||
enc3 = key.indexOf(value.charAt(i++)); | ||
enc4 = key.indexOf(value.charAt(i++)); | ||
chr1 = (enc1 << 2) | (enc2 >> 4); | ||
chr2 = ((enc2 & 15) << 4) | (enc3 >> 2); | ||
chr3 = ((enc3 & 3) << 6) | enc4; | ||
base64 = base64 + String.fromCharCode(chr1); | ||
if (enc3 != 64 && chr2 != 0) { | ||
base64 = base64 + String.fromCharCode(chr2); | ||
} | ||
if (enc4 != 64 && chr3 != 0) { | ||
base64 = base64 + String.fromCharCode(chr3); | ||
} | ||
} | ||
return base64; | ||
} | ||
/** | ||
@@ -158,15 +135,24 @@ * A deferred represents some asynchronous work that is not yet finished, which | ||
Deferred.promiseConstructor = Promise; | ||
// Taken from: https://stackoverflow.com/questions/38552003/how-to-decode-jwt-token-in-javascript-without-using-a-library | ||
export function decodeJWTPayload(token) { | ||
// Regex checks for base64url format | ||
const base64UrlRegex = /^([a-z0-9_-]{4})*($|[a-z0-9_-]{3}=?$|[a-z0-9_-]{2}(==)?$)$/i; | ||
export function decodeJWT(token) { | ||
const parts = token.split('.'); | ||
if (parts.length !== 3) { | ||
throw new Error('JWT is not valid: not a JWT structure'); | ||
throw new AuthInvalidJwtError('Invalid JWT structure'); | ||
} | ||
if (!base64UrlRegex.test(parts[1])) { | ||
throw new Error('JWT is not valid: payload is not in base64url format'); | ||
// Regex checks for base64url format | ||
for (let i = 0; i < parts.length; i++) { | ||
if (!BASE64URL_REGEX.test(parts[i])) { | ||
throw new AuthInvalidJwtError('JWT not in base64url format'); | ||
} | ||
} | ||
const base64Url = parts[1]; | ||
return JSON.parse(decodeBase64URL(base64Url)); | ||
const data = { | ||
// using base64url lib | ||
header: JSON.parse(stringFromBase64URL(parts[0])), | ||
payload: JSON.parse(stringFromBase64URL(parts[1])), | ||
signature: base64UrlToUint8Array(parts[2]), | ||
raw: { | ||
header: parts[0], | ||
payload: parts[1], | ||
}, | ||
}; | ||
return data; | ||
} | ||
@@ -238,5 +224,2 @@ /** | ||
} | ||
function base64urlencode(str) { | ||
return btoa(str).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, ''); | ||
} | ||
export async function generatePKCEChallenge(verifier) { | ||
@@ -251,3 +234,3 @@ const hasCryptoSupport = typeof crypto !== 'undefined' && | ||
const hashed = await sha256(verifier); | ||
return base64urlencode(hashed); | ||
return stringToBase64URL(hashed); | ||
} | ||
@@ -283,2 +266,28 @@ export async function getCodeChallengeAndMethod(storage, storageKey, isPasswordRecovery = false) { | ||
} | ||
export function validateExp(exp) { | ||
if (!exp) { | ||
throw new Error('Missing exp claim'); | ||
} | ||
const timeNow = Math.floor(Date.now() / 1000); | ||
if (exp <= timeNow) { | ||
throw new Error('JWT has expired'); | ||
} | ||
} | ||
export function getAlgorithm(alg) { | ||
switch (alg) { | ||
case 'RS256': | ||
return { | ||
name: 'RSASSA-PKCS1-v1_5', | ||
hash: { name: 'SHA-256' }, | ||
}; | ||
case 'ES256': | ||
return { | ||
name: 'ECDSA', | ||
namedCurve: 'P-256', | ||
hash: { name: 'SHA-256' }, | ||
}; | ||
default: | ||
throw new Error('Invalid alg claim'); | ||
} | ||
} | ||
//# sourceMappingURL=helpers.js.map |
@@ -1014,3 +1014,28 @@ import { AuthError } from './errors'; | ||
}; | ||
export declare type JwtHeader = { | ||
alg: 'RS256' | 'ES256' | 'HS256'; | ||
kid: string; | ||
typ: string; | ||
}; | ||
export declare type RequiredClaims = { | ||
iss: string; | ||
sub: string; | ||
aud: string | string[]; | ||
exp: number; | ||
iat: number; | ||
role: string; | ||
aal: AuthenticatorAssuranceLevels; | ||
session_id: string; | ||
}; | ||
export declare type JwtPayload = RequiredClaims & { | ||
[key: string]: any; | ||
}; | ||
export interface JWK { | ||
kty: 'RSA' | 'EC' | 'oct'; | ||
key_ops: string[]; | ||
alg?: string; | ||
kid?: string; | ||
[key: string]: any; | ||
} | ||
export {}; | ||
//# sourceMappingURL=types.d.ts.map |
@@ -1,2 +0,2 @@ | ||
export declare const version = "2.68.1-rc.1"; | ||
export declare const version = "2.69.0-rc.2"; | ||
//# sourceMappingURL=version.d.ts.map |
@@ -1,2 +0,2 @@ | ||
export const version = '2.68.1-rc.1'; | ||
export const version = '2.69.0-rc.2'; | ||
//# sourceMappingURL=version.js.map |
{ | ||
"name": "@supabase/gotrue-js", | ||
"version": "2.68.1-rc.1", | ||
"version": "2.69.0-rc.2", | ||
"private": false, | ||
@@ -5,0 +5,0 @@ "description": "Official client library for Supabase Auth", |
@@ -31,1 +31,3 @@ import { version } from './version' | ||
} | ||
export const BASE64URL_REGEX = /^([a-z0-9_-]{4})*($|[a-z0-9_-]{3}$|[a-z0-9_-]{2}$)$/i |
@@ -160,1 +160,7 @@ import { WeakPasswordReasons } from './types' | ||
} | ||
export class AuthInvalidJwtError extends CustomAuthError { | ||
constructor(message: string) { | ||
super(message, 'AuthInvalidJwtError', 400, 'invalid_jwt') | ||
} | ||
} |
@@ -1,3 +0,5 @@ | ||
import { API_VERSION_HEADER_NAME } from './constants' | ||
import { SupportedStorage } from './types' | ||
import { API_VERSION_HEADER_NAME, BASE64URL_REGEX } from './constants' | ||
import { AuthInvalidJwtError } from './errors' | ||
import { base64UrlToUint8Array, stringFromBase64URL, stringToBase64URL } from './base64url' | ||
import { JwtHeader, JwtPayload, SupportedStorage } from './types' | ||
@@ -144,30 +146,2 @@ export function expiresAt(expiresIn: number) { | ||
export function decodeBase64URL(value: string): string { | ||
const key = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=' | ||
let base64 = '' | ||
let chr1, chr2, chr3 | ||
let enc1, enc2, enc3, enc4 | ||
let i = 0 | ||
value = value.replace('-', '+').replace('_', '/') | ||
while (i < value.length) { | ||
enc1 = key.indexOf(value.charAt(i++)) | ||
enc2 = key.indexOf(value.charAt(i++)) | ||
enc3 = key.indexOf(value.charAt(i++)) | ||
enc4 = key.indexOf(value.charAt(i++)) | ||
chr1 = (enc1 << 2) | (enc2 >> 4) | ||
chr2 = ((enc2 & 15) << 4) | (enc3 >> 2) | ||
chr3 = ((enc3 & 3) << 6) | enc4 | ||
base64 = base64 + String.fromCharCode(chr1) | ||
if (enc3 != 64 && chr2 != 0) { | ||
base64 = base64 + String.fromCharCode(chr2) | ||
} | ||
if (enc4 != 64 && chr3 != 0) { | ||
base64 = base64 + String.fromCharCode(chr3) | ||
} | ||
} | ||
return base64 | ||
} | ||
/** | ||
@@ -198,19 +172,34 @@ * A deferred represents some asynchronous work that is not yet finished, which | ||
// Taken from: https://stackoverflow.com/questions/38552003/how-to-decode-jwt-token-in-javascript-without-using-a-library | ||
export function decodeJWTPayload(token: string) { | ||
// Regex checks for base64url format | ||
const base64UrlRegex = /^([a-z0-9_-]{4})*($|[a-z0-9_-]{3}=?$|[a-z0-9_-]{2}(==)?$)$/i | ||
export function decodeJWT(token: string): { | ||
header: JwtHeader | ||
payload: JwtPayload | ||
signature: Uint8Array | ||
raw: { | ||
header: string | ||
payload: string | ||
} | ||
} { | ||
const parts = token.split('.') | ||
if (parts.length !== 3) { | ||
throw new Error('JWT is not valid: not a JWT structure') | ||
throw new AuthInvalidJwtError('Invalid JWT structure') | ||
} | ||
if (!base64UrlRegex.test(parts[1] as string)) { | ||
throw new Error('JWT is not valid: payload is not in base64url format') | ||
// Regex checks for base64url format | ||
for (let i = 0; i < parts.length; i++) { | ||
if (!BASE64URL_REGEX.test(parts[i] as string)) { | ||
throw new AuthInvalidJwtError('JWT not in base64url format') | ||
} | ||
} | ||
const base64Url = parts[1] as string | ||
return JSON.parse(decodeBase64URL(base64Url)) | ||
const data = { | ||
// using base64url lib | ||
header: JSON.parse(stringFromBase64URL(parts[0])), | ||
payload: JSON.parse(stringFromBase64URL(parts[1])), | ||
signature: base64UrlToUint8Array(parts[2]), | ||
raw: { | ||
header: parts[0], | ||
payload: parts[1], | ||
}, | ||
} | ||
return data | ||
} | ||
@@ -292,6 +281,2 @@ | ||
function base64urlencode(str: string) { | ||
return btoa(str).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '') | ||
} | ||
export async function generatePKCEChallenge(verifier: string) { | ||
@@ -310,3 +295,3 @@ const hasCryptoSupport = | ||
const hashed = await sha256(verifier) | ||
return base64urlencode(hashed) | ||
return stringToBase64URL(hashed) | ||
} | ||
@@ -351,1 +336,29 @@ | ||
} | ||
export function validateExp(exp: number) { | ||
if (!exp) { | ||
throw new Error('Missing exp claim') | ||
} | ||
const timeNow = Math.floor(Date.now() / 1000) | ||
if (exp <= timeNow) { | ||
throw new Error('JWT has expired') | ||
} | ||
} | ||
export function getAlgorithm(alg: 'RS256' | 'ES256'): RsaHashedImportParams | EcKeyImportParams { | ||
switch (alg) { | ||
case 'RS256': | ||
return { | ||
name: 'RSASSA-PKCS1-v1_5', | ||
hash: { name: 'SHA-256' }, | ||
} | ||
case 'ES256': | ||
return { | ||
name: 'ECDSA', | ||
namedCurve: 'P-256', | ||
hash: { name: 'SHA-256' }, | ||
} | ||
default: | ||
throw new Error('Invalid alg claim') | ||
} | ||
} |
@@ -1202,1 +1202,30 @@ import { AuthError } from './errors' | ||
} | ||
export type JwtHeader = { | ||
alg: 'RS256' | 'ES256' | 'HS256' | ||
kid: string | ||
typ: string | ||
} | ||
export type RequiredClaims = { | ||
iss: string | ||
sub: string | ||
aud: string | string[] | ||
exp: number | ||
iat: number | ||
role: string | ||
aal: AuthenticatorAssuranceLevels | ||
session_id: string | ||
} | ||
export type JwtPayload = RequiredClaims & { | ||
[key: string]: any | ||
} | ||
export interface JWK { | ||
kty: 'RSA' | 'EC' | 'oct' | ||
key_ops: string[] | ||
alg?: string | ||
kid?: string | ||
[key: string]: any | ||
} |
@@ -1,1 +0,1 @@ | ||
export const version = '2.68.1-rc.1' | ||
export const version = '2.69.0-rc.2' |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
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
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
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
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
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
Sorry, the diff of this file is too big to display
905035
86867
147
16248
7
0