This Klient extension allows you to fetch JWT for current user with its credentials, store it, and authenticate requests with fetched token. The refresh token process is also supported. Every parts of workflow can be adapted directly from parameters.
Install package with your favorite package manager :
# With NPM
$ npm install @klient/jwt
# With YARN
$ yarn add @klient/jwt
Then import the extension in your code :
import Klient from '@klient/core';
//
// Register extension
//
import '@klient/jwt';
//
// Build Klient instance
//
const klient = new Klient('...');
//
// See loaded extension
//
console.log(klient.extensions); // Print ["@klient/jwt"]
import Klient from '@klient/core';
//
// Register extension
//
import '@klient/jwt';
//
// Create klient instance with registered extension
//
const klient = new Klient({
jwt: {
auth: {
url: '/auth',
method: 'POST'
}
}
});
//
// Get a fresh token
//
klient
.login({ username: '...', password: '...' })
.then(data => {
console.log(data); // API response content
})
;
//
// Check user authentication
//
console.log(klient.jwt.isAuthenticated) // Print true
//
// Listen for requests
//
klient.on('request', e => {
console.log(e.config.headers.Authorization); // Print "Bearer <received token>"
});
//
// Make a request to private url
//
klient.request('/private').then(...)
The JWT parameters allow you to configure whole jwt process.
const klient = new Klient({
jwt: {
login: {
// Url to use when call login method
url: '/auth',
// Method to use when call login method
method: 'POST',
// Rest of request static configuration
// All axios options are available
headers: {
'Content-Type': 'application/json'
},
// Configure request made on login action
configure: (credentials, config, jwt) => {
config.data = {
username: credentials[0],
password: credentials[0],
}
},
// Map login response to authentication state
map: (response, config, jwt) => {
const { token, refresh_token } = response.data;
return {
token,
refreshToken: refresh_token,
tokenExp: jwt.decode(token).exp,
refreshTokenExp: jwt.decode(refresh_token).exp,
}
}
},
refresh: {
// Url to use when refresh action is invoked
url: '/auth/refresh',
// Method to use to refresh credentials
method: 'POST',
// Rest of request static configuration
// All axios options are available
headers: {
'Content-Type': 'application/json'
},
// Configure request made on refresh credentials action
configure: (refreshToken, config, jwt) => {
config.data.customRefreshTokenKey = refreshToken;
},
// Map refresh credentials response to authentication state
map: (response, config, jwt) => {
const { token, refresh_token } = response.data;
return {
token,
refreshToken: refresh_token,
tokenExp: jwt.decode(token).exp,
refreshTokenExp: jwt.decode(refresh_token).exp,
}
}
},
// Authenticate request manually with current authentication state
authenticate: (config, jwt) => {
config.headers = config.headers || {};
config.headers.Authorization = 'Bearer ' + jwt.token
},
// Persist authentication state in a storage
// See @klient/storage
storage: {
type: 'localStorage',
options: {
// ...
}
},
// Set jwt decode static options
decode_options: {
// jwt decode options
}
}
})
JWT service listen RequestEvent and is able to add token in request config if an authenticated user is detected. The exact behavious is described below :
-
If user isn't authenticated, jwt service ignores requests.
-
If user has a valid token, jwt service add it in request config.
-
If user has an expired token, but have a valid refresh token, jwt service will try to refresh token before append it in request config. (This will suspend execution of request, and will reject it if credentials are not refreshable)
-
If user has an expired token, and no valid refresh token, the jwt service will emit CredentialsExpiredEvent and reject the request after .
Authentication can be disabled by using request context :
import Klient from '@klient/core';
//
// Register extension
//
import '@klient/jwt';
//
// Build Klient instance
//
const klient = new Klient('...');
klient.request({
url: '/public',
context: {
authenticate: false // This means "Do not authenticate request"
}
});
The JWT service is the orchestrator of JWT worklow by analyzing at every request if a stored token is valid, else if it can be refreshed, etc..
Get JWT with user credentials.
login(credentials: any): Promise<AxiosResponse.data>
Example
import Klient from '@klient/core';
//
// Register extension
//
import '@klient/jwt';
//
// Build Klient instance
//
const klient = new Klient({
jwt: {
login: {
url '/auth',
method: 'POST'
}
}
});
//
// Construct credentials as they are expected in API
//
const credentials = { username: '...', password: '...' };
//
// Login
//
klient.login(credentials).then(data => {
// At this point jwt service has created a state to store authentication data
// and user is considerated as logged.
});
Remove stored user authentication state.
logout(): Promise<void>
Example
import Klient from '@klient/core';
//
// Register extension
//
import '@klient/jwt';
//
// Build Klient instance
//
const klient = new Klient({
jwt: {
login: {
url '/auth',
method: 'POST'
}
}
});
//
// Construct credentials as they are expected in API
//
const credentials = { username: '...', password: '...' };
//
// Login
//
await klient.login(credentials).then(data => {
// At this point jwt service has created a state to store authentication data
// and user is considerated as logged.
});
klient.jwt.isAuthenticated; // True
klient.jwt.state; // { token: 'value', ... }
//
// Logout
//
klient.logout().then(() => {
klient.jwt.isAuthenticated; // False
klient.jwt.state; // undefined
});
alias =
jwt:login
The LoginEvent is emitted when new token is stored in authentication state (after login method OR during a request when token has been refreshed).
Properties
Name | Type | Description |
---|---|---|
response | AxiosResponse |
The login/refresh response received from API. |
token | string |
The response token. |
decodedToken | object |
The decoded token. |
refreshToken | string | undefined |
The response refresh token. |
alias =
jwt:expired
The CredentialsExpiredEvent is emitted on request execution if user credentials is expired and cannot be refreshed.
Properties
Name | Type | Description |
---|---|---|
relatedEvent | RequestEvent |
The related event containing the request. |
error | AxiosError | Error |
The related error. |
alias =
jwt:logout
The LogoutEvent is emitted before authentication state deletion when calling logout method.