@limoncello-framework/oauth-client v0.1.5
Summary
Client side OAuth 2 implementation based on RFC 6749 - The OAuth 2.0 Authorization Framework.
Basic usage (complete sample below in Usage section)
const authorizer = ...;
// Request token
authorizer.password('user-name', 'password')
.then(token => {
// you got a token
})
.catch(error => {
// something's broken
});
// Refresh token
authorizer.refresh('old-token-value')
.then(token => {
// you got a new token
})
.catch(error => {
// something's broken
})
Installation
$ npm install --save-dev @limoncello-framework/oauth-client
or
$ yarn add --dev @limoncello-framework/oauth-client
Features
RFC 6749 defines the following authorization grants
- Authorization Code Grant - implemented (steps 4.1.3 and 4.1.4 of the spec).
- Implicit Grant - out of the project scope (nothing to implement).
- Resource Owner Password Credentials Grant - implemented.
- Client Credentials Grant - implemented.
Additionally it describes Refreshing an Access Token process - implemented.
Usage
The library is designed to focus on the RFC logic and error handling leaving such minor technical details as sending data over network to a developer's choice. It requires from a developer to implement the following interface
interface ClientRequestsInterface {
/**
* Sends form data to a OAuth Server token endpoint.
*/
sendForm(data: any, addAuth: boolean): Promise<Response>;
}
ClientRequestsInterface
could be implemented with jQuery, XMLHttpRequest, Fetch API, Node.js and etc. Here is an example built with Fetch API for Resource Owner Password Credentials Grant
and Refreshing an Access Token
.
import { Authorizer } from '@limoncello-framework/oauth-client';
const clientRequests = {
sendForm(data, addAuth) {
// fill it a form
// for more see https://developer.mozilla.org/en-US/docs/Web/API/FormData/FormData
let form = new FormData();
Object.getOwnPropertyNames(data).forEach((name) => form.append(name, data[name]));
// see https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch
// for a full list of available options.
let init = {
body: form,
method: "post",
mode: "cors",
credentials: "omit",
cache: "no-cache",
};
if (addAuth === true) {
// add client auth info or throw an exception if not applicable
init.headers = new Headers({Authorization: 'Basic ...'});
}
return fetch('http://your-domain.name/token', init);
}
};
const authorizer = new Authorizer(clientRequests);
// Request token
authorizer.password('user-name', 'password', 'optional,list,of,scopes,separated,by,comma')
.then(token => {
// see https://tools.ietf.org/html/rfc6749#section-5.1
console.log('token value ' + token.access_token);
console.log('token will expire in (seconds) ' + token.expires_in);
console.log('optional refresh token ' + token.refresh_token);
})
.catch(error => {
if (error.reason !== undefined) {
// see https://tools.ietf.org/html/rfc6749#section-5.2
console.error('Authentication failed. Reason: ' + error.reason.error);
} else {
// invalid token URL, network error, invalid response format or server-side error
console.error('Error occurred: ' + error.message);
}
});
// Refresh token
authorizer.refresh('old-token-value')
.then(token => {
// you got a new token
})
.catch(error => {
// something's broken
})
Testing
- Clone the repository.
- Install dependencies with
npm install
oryarn install
. - Run tests with
npm run test
oryarn test
.
Questions
Feel free to open an issue marked as 'Question' in its title.