Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

axios-jwt

Package Overview
Dependencies
Maintainers
3
Versions
36
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

axios-jwt - npm Package Compare versions

Comparing version 1.8.0 to 2.0.0

dist/storage.android.d.ts

67

dist/index.js

@@ -43,6 +43,8 @@ "use strict";

exports.authTokenInterceptor = exports.useAuthTokenInterceptor = exports.applyAuthTokenInterceptor = exports.refreshTokenIfNeeded = exports.getAccessToken = exports.getRefreshToken = exports.clearAuthTokens = exports.setAccessToken = exports.setAuthTokens = exports.isLoggedIn = exports.STORAGE_KEY = void 0;
var axios_1 = __importDefault(require("axios"));
var jwt_decode_1 = __importDefault(require("jwt-decode"));
var storage_1 = __importDefault(require("./storage"));
// a little time before expiration to try refresh (seconds)
var EXPIRE_FUDGE = 10;
exports.STORAGE_KEY = "auth-tokens-" + process.env.NODE_ENV;
exports.STORAGE_KEY = "auth-tokens-".concat(process.env.NODE_ENV);
// EXPORTS

@@ -54,3 +56,3 @@ /**

var isLoggedIn = function () {
var token = exports.getRefreshToken();
var token = (0, exports.getRefreshToken)();
return !!token;

@@ -63,3 +65,5 @@ };

*/
var setAuthTokens = function (tokens) { return localStorage.setItem(exports.STORAGE_KEY, JSON.stringify(tokens)); };
var setAuthTokens = function (tokens) {
return storage_1.default.setItem(exports.STORAGE_KEY, JSON.stringify(tokens));
};
exports.setAuthTokens = setAuthTokens;

@@ -76,3 +80,3 @@ /**

tokens.accessToken = token;
exports.setAuthTokens(tokens);
(0, exports.setAuthTokens)(tokens);
};

@@ -83,3 +87,3 @@ exports.setAccessToken = setAccessToken;

*/
var clearAuthTokens = function () { return localStorage.removeItem(exports.STORAGE_KEY); };
var clearAuthTokens = function () { return storage_1.default.removeItem(exports.STORAGE_KEY); };
exports.clearAuthTokens = clearAuthTokens;

@@ -119,3 +123,3 @@ /**

case 0:
accessToken = exports.getAccessToken();
accessToken = (0, exports.getAccessToken)();
if (!(!accessToken || isTokenExpired(accessToken))) return [3 /*break*/, 2];

@@ -139,4 +143,4 @@ return [4 /*yield*/, refreshToken(requestRefresh)];

if (!axios.interceptors)
throw new Error("invalid axios instance: " + axios);
axios.interceptors.request.use(exports.authTokenInterceptor(config));
throw new Error("invalid axios instance: ".concat(axios));
axios.interceptors.request.use((0, exports.authTokenInterceptor)(config));
};

@@ -154,3 +158,3 @@ exports.applyAuthTokenInterceptor = applyAuthTokenInterceptor;

var getAuthTokens = function () {
var rawTokens = localStorage.getItem(exports.STORAGE_KEY);
var rawTokens = storage_1.default.getItem(exports.STORAGE_KEY);
if (!rawTokens)

@@ -164,3 +168,3 @@ return;

if (error instanceof SyntaxError) {
error.message = "Failed to parse auth tokens: " + rawTokens;
error.message = "Failed to parse auth tokens: ".concat(rawTokens);
throw error;

@@ -189,4 +193,4 @@ }

var getTimestampFromToken = function (token) {
var decoded = jwt_decode_1.default(token);
return decoded === null || decoded === void 0 ? void 0 : decoded.exp;
var decoded = (0, jwt_decode_1.default)(token);
return decoded.exp;
};

@@ -217,3 +221,3 @@ /**

case 0:
refreshToken = exports.getRefreshToken();
refreshToken = (0, exports.getRefreshToken)();
if (!refreshToken)

@@ -229,3 +233,3 @@ throw new Error('No refresh token available');

if (!(typeof newTokens === 'object' && (newTokens === null || newTokens === void 0 ? void 0 : newTokens.accessToken))) return [3 /*break*/, 4];
return [4 /*yield*/, exports.setAuthTokens(newTokens)];
return [4 /*yield*/, (0, exports.setAuthTokens)(newTokens)];
case 3:

@@ -236,3 +240,3 @@ _b.sent();

if (!(typeof newTokens === 'string')) return [3 /*break*/, 6];
return [4 /*yield*/, exports.setAccessToken(newTokens)];
return [4 /*yield*/, (0, exports.setAccessToken)(newTokens)];
case 5:

@@ -244,11 +248,17 @@ _b.sent();

error_1 = _b.sent();
status_1 = (_a = error_1 === null || error_1 === void 0 ? void 0 : error_1.response) === null || _a === void 0 ? void 0 : _a.status;
if (status_1 === 401 || status_1 === 422) {
// The refresh token is invalid so remove the stored tokens
localStorage.removeItem(exports.STORAGE_KEY);
throw new Error("Got " + status_1 + " on token refresh; clearing both auth tokens");
// Failed to refresh token
if (axios_1.default.isAxiosError(error_1)) {
status_1 = (_a = error_1.response) === null || _a === void 0 ? void 0 : _a.status;
if (status_1 === 401 || status_1 === 422) {
// The refresh token is invalid so remove the stored tokens
storage_1.default.removeItem(exports.STORAGE_KEY);
throw new Error("Got ".concat(status_1, " on token refresh; clearing both auth tokens"));
}
}
// A different error, probably network error
if (error_1 instanceof Error) {
throw new Error("Failed to refresh auth token: ".concat(error_1.message));
}
else {
// A different error, probably network error
throw new Error("Failed to refresh auth token: " + error_1.message);
throw new Error('Failed to refresh auth token and failed to parse error');
}

@@ -280,3 +290,3 @@ return [3 /*break*/, 9];

// We need refresh token to do any authenticated requests
if (!exports.getRefreshToken())
if (!(0, exports.getRefreshToken)())
return [2 /*return*/, requestConfig

@@ -292,3 +302,3 @@ // Queue the request if another refresh request is currently happening

if (requestConfig.headers) {
requestConfig.headers[header] = "" + headerPrefix + token;
requestConfig.headers[header] = "".concat(headerPrefix).concat(token);
}

@@ -302,3 +312,3 @@ return requestConfig;

_a.trys.push([1, 3, , 4]);
return [4 /*yield*/, exports.refreshTokenIfNeeded(requestRefresh)];
return [4 /*yield*/, (0, exports.refreshTokenIfNeeded)(requestRefresh)];
case 2:

@@ -312,3 +322,3 @@ accessToken = _a.sent();

declineQueue(error_2);
throw new Error("Unable to refresh access token for request due to token refresh error: " + error_2.message);
throw new Error("Unable to refresh access token for request due to token refresh error: ".concat(error_2.message));
}

@@ -318,4 +328,5 @@ return [3 /*break*/, 4];

// add token to headers
if (accessToken && requestConfig.headers)
requestConfig.headers[header] = "" + headerPrefix + accessToken;
if (accessToken && requestConfig.headers) {
requestConfig.headers[header] = "".concat(headerPrefix).concat(accessToken);
}
return [2 /*return*/, requestConfig];

@@ -322,0 +333,0 @@ }

{
"name": "axios-jwt",
"version": "1.8.0",
"version": "2.0.0",
"description": "Axios interceptor to store, use, and refresh tokens for authentication.",

@@ -18,2 +18,3 @@ "main": "dist/index.js",

"@types/jsonwebtoken": "^8.5.1",
"@types/jwt-decode": "^3.1.0",
"@typescript-eslint/eslint-plugin": "^4.21.0",

@@ -26,5 +27,6 @@ "@typescript-eslint/parser": "^4.21.0",

"ts-jest": "^26.5.4",
"typescript": "^4.2.4"
"typescript": "^4.6.4"
},
"peerDependencies": {
"@react-native-async-storage/async-storage": "1.15.17",
"axios": "^0.27.0"

@@ -31,0 +33,0 @@ },

# axios-jwt
Store, clear, transmit and automatically refresh JWT authentication tokens.
Store, clear, transmit and automatically refresh JWT authentication tokens. This library can be used in both web and react-native projects.

@@ -10,3 +10,3 @@ ## What does it do?

The interceptor automatically adds an access token header (default: `Authorization`) to all requests.
It stores `accessToken` and `refreshToken` in `localStorage` and reads them when needed.
It stores `accessToken` and `refreshToken` in `localStorage` (web) or 'AsyncStorage' (React Native) and reads them when needed.

@@ -16,2 +16,27 @@ It parses the expiration time of your access token and checks to see if it is expired before every request. If it has expired, a request to

## Installation instructions
### Install axios-jwt
```bash
npm install --save axios-jwt # or `yarn add axios-jwt`
```
### Additional steps for React Native projects
You will also need to install react-native-async-storage in order to be able to store and retrieve tokens.
#### Expo
```bash
expo install @react-native-async-storage/async-storage
```
### React Native
```bash
npm install --save @react-native-async-storage/async-storage # or `yarn add @react-native-async-storage/async-storage`
npx pod-install # installs the native iOS packages
```
## How do I use it?

@@ -78,3 +103,3 @@

// 5. Clear the auth tokens from localstorage
// 5. Remove the auth tokens from storage
const logout = () => clearAuthTokens()

@@ -81,0 +106,0 @@

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

import { AxiosInstance, AxiosRequestConfig } from 'axios'
import jwtDecode from 'jwt-decode'
import axios, { AxiosInstance, AxiosRequestConfig } from 'axios'
import jwtDecode, { JwtPayload } from 'jwt-decode'
import Storage from './storage'

@@ -29,3 +30,4 @@ // a little time before expiration to try refresh (seconds)

*/
export const setAuthTokens = (tokens: IAuthTokens): void => localStorage.setItem(STORAGE_KEY, JSON.stringify(tokens))
export const setAuthTokens = (tokens: IAuthTokens): void =>
Storage.setItem(STORAGE_KEY, JSON.stringify(tokens))

@@ -49,3 +51,3 @@ /**

*/
export const clearAuthTokens = (): void => localStorage.removeItem(STORAGE_KEY)
export const clearAuthTokens = (): void => Storage.removeItem(STORAGE_KEY)

@@ -81,3 +83,5 @@ /**

*/
export const refreshTokenIfNeeded = async (requestRefresh: TokenRefreshRequest): Promise<Token | undefined> => {
export const refreshTokenIfNeeded = async (
requestRefresh: TokenRefreshRequest
): Promise<Token | undefined> => {
// use access token (if we have it)

@@ -101,3 +105,6 @@ let accessToken = getAccessToken()

*/
export const applyAuthTokenInterceptor = (axios: AxiosInstance, config: IAuthTokenInterceptorConfig): void => {
export const applyAuthTokenInterceptor = (
axios: AxiosInstance,
config: IAuthTokenInterceptorConfig
): void => {
if (!axios.interceptors) throw new Error(`invalid axios instance: ${axios}`)

@@ -119,3 +126,3 @@ axios.interceptors.request.use(authTokenInterceptor(config))

const getAuthTokens = (): IAuthTokens | undefined => {
const rawTokens = localStorage.getItem(STORAGE_KEY)
const rawTokens = Storage.getItem(STORAGE_KEY)
if (!rawTokens) return

@@ -153,5 +160,5 @@

const getTimestampFromToken = (token: Token): number | undefined => {
const decoded = jwtDecode<{ [key: string]: number }>(token)
const decoded = jwtDecode<JwtPayload>(token)
return decoded?.exp
return decoded.exp
}

@@ -197,13 +204,18 @@

throw new Error('requestRefresh must either return a string or an object with an accessToken')
// eslint-disable-next-line @typescript-eslint/no-explicit-any
} catch (error: any) {
} catch (error) {
// Failed to refresh token
const status = error?.response?.status
if (status === 401 || status === 422) {
// The refresh token is invalid so remove the stored tokens
localStorage.removeItem(STORAGE_KEY)
throw new Error(`Got ${status} on token refresh; clearing both auth tokens`)
if (axios.isAxiosError(error)) {
const status = error.response?.status
if (status === 401 || status === 422) {
// The refresh token is invalid so remove the stored tokens
Storage.removeItem(STORAGE_KEY)
throw new Error(`Got ${status} on token refresh; clearing both auth tokens`)
}
}
// A different error, probably network error
if (error instanceof Error) {
throw new Error(`Failed to refresh auth token: ${error.message}`)
} else {
// A different error, probably network error
throw new Error(`Failed to refresh auth token: ${error.message}`)
throw new Error('Failed to refresh auth token and failed to parse error')
}

@@ -232,41 +244,48 @@ } finally {

*/
export const authTokenInterceptor = ({
header = 'Authorization',
headerPrefix = 'Bearer ',
requestRefresh,
}: IAuthTokenInterceptorConfig) => async (requestConfig: AxiosRequestConfig): Promise<AxiosRequestConfig> => {
// We need refresh token to do any authenticated requests
if (!getRefreshToken()) return requestConfig
export const authTokenInterceptor =
({
header = 'Authorization',
headerPrefix = 'Bearer ',
requestRefresh,
}: IAuthTokenInterceptorConfig) =>
async (requestConfig: AxiosRequestConfig): Promise<AxiosRequestConfig> => {
// We need refresh token to do any authenticated requests
if (!getRefreshToken()) return requestConfig
// Queue the request if another refresh request is currently happening
if (isRefreshing) {
return new Promise((resolve, reject) => {
queue.push({ resolve, reject })
})
.then((token) => {
if (requestConfig.headers) {
requestConfig.headers[header] = `${headerPrefix}${token}`
}
return requestConfig
// Queue the request if another refresh request is currently happening
if (isRefreshing) {
return new Promise((resolve, reject) => {
queue.push({ resolve, reject })
})
.catch(Promise.reject)
}
.then((token) => {
if (requestConfig.headers) {
requestConfig.headers[header] = `${headerPrefix}${token}`
}
return requestConfig
})
.catch(Promise.reject)
}
// Do refresh if needed
let accessToken
try {
accessToken = await refreshTokenIfNeeded(requestRefresh)
resolveQueue(accessToken)
} catch (error: unknown) {
if (error instanceof Error) {
declineQueue(error)
throw new Error(`Unable to refresh access token for request due to token refresh error: ${error.message}`)
// Do refresh if needed
let accessToken
try {
accessToken = await refreshTokenIfNeeded(requestRefresh)
resolveQueue(accessToken)
} catch (error: unknown) {
if (error instanceof Error) {
declineQueue(error)
throw new Error(
`Unable to refresh access token for request due to token refresh error: ${error.message}`
)
}
}
// add token to headers
if (accessToken && requestConfig.headers) {
requestConfig.headers[header] = `${headerPrefix}${accessToken}`
}
return requestConfig
}
// add token to headers
if (accessToken && requestConfig.headers) requestConfig.headers[header] = `${headerPrefix}${accessToken}`
return requestConfig
}
type RequestsQueue = {

@@ -273,0 +292,0 @@ resolve: (value?: unknown) => void

import { STORAGE_KEY, refreshTokenIfNeeded } from '../src'
import jwt from 'jsonwebtoken'
import { AxiosError } from 'axios'
function makeAxiosErrorWithStatusCode(statusCode: number) {
const error = new AxiosError(
'Server error',
'ECONNABORTED',
{},
{},
{
status: statusCode,
data: {},
config: {},
headers: {},
statusText: '',
}
)
return error
}
describe('refreshTokenIfNeeded', () => {

@@ -54,6 +73,3 @@ it('throws an error if the requestRefresh function threw one', async () => {

const requestRefresh = async () => {
const error: any = new Error('Server error')
error.response = {
status: 401,
}
const error = makeAxiosErrorWithStatusCode(401)

@@ -94,6 +110,3 @@ throw error

const requestRefresh = async () => {
const error: any = new Error('Server error')
error.response = {
status: 422,
}
const error = makeAxiosErrorWithStatusCode(422)

@@ -100,0 +113,0 @@ throw error

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

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