• Stars
    star
    295
  • Rank 136,365 (Top 3 %)
  • Language
    CoffeeScript
  • License
    Other
  • Created about 11 years ago
  • Updated almost 7 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

A simple OAuth 2 endpoint for Restify

OAuth 2 Endpoints for Restify

This package provides a very simple OAuth 2.0 endpoint for the Restify framework. In particular, it implements the Client Credentials and Resource Owner Password Credentials flows only.

What You Get

If you provide Restify–OAuth2 with the appropriate hooks, it will:

  • Set up a token endpoint, which returns access token responses or correctly-formatted error responses.
  • For all other resources, when an access token is sent via the Authorization header, it will validate it:
  • If no access token is sent, it ensures that req.username is set to null; furthermore, none of your hooks are called, so you can be sure that no properties that they set are present.
    • You can then check for these conditions whenever there is a resource you want to protect.
    • If the user tries to access a protected resource, you can use Restify–OAuth2's res.sendUnauthenticated() to send appropriate 401 errors with helpful WWW-Authenticate and Link headers, or its res.sendUnauthorized() to send appropriate 403 errors with similar headers.

Use and Configuration

To use Restify–OAuth2, you'll need to pass it your server plus some options, including the hooks discussed below. Restify–OAuth2 also depends on the built-in authorizationParser and bodyParser plugins, the latter with mapParams set to false. So in short, it looks like this:

var restify = require("restify");
var restifyOAuth2 = require("restify-oauth2");

var server = restify.createServer({ name: "My cool server", version: "1.0.0" });
server.use(restify.authorizationParser());
server.use(restify.bodyParser({ mapParams: false }));

restifyOAuth2.cc(server, options);
// or
restifyOAuth2.ropc(server, options);

Unfortunately, Restify–OAuth2 can't be a simple Restify plugin. It needs to install a route for the token endpoint, whereas plugins simply run on every request and don't modify the server's routing table.

Options

The options you pass to Restify–OAuth2 depend heavily on which of the two flows you are choosing. There are some options common to both flows, but the options.hooks hash will vary depending on the flow. Once you provide the appropriate hooks, you get an OAuth 2 implementation for free.

Client Credentials Hooks

The idea behind this very simple OAuth 2 flow is that your API clients identify themselves with client IDs and secrets, and if those values authenticate, you grant them an access token they can use for further requests. The advantage of this over simply requiring basic access authentication headers on every request is that now you can set those tokens to expire, or revoke them if they fall in to the wrong hands.

To install Restify–OAuth2's client credentials flow into your infrastructure, you will need to provide it with the following hooks in the options.hooks hash. You can see some example CC hooks in the demo application.

grantClientToken({ clientId, clientSecret }, req, cb)

Checks that the API client is authorized to use your API, and has the correct secret. It should call back with a new token for that client if so, or false if the credentials are incorrect. It can also call back with an error if there was some internal server error while validating the credentials.

authenticateToken(token, req, cb)

Checks that a token is valid, i.e. that it was granted in the past by grantClientToken. It should call back with true if so, or false if the token is invalid. It can also call back with an error if there was some internal server error while looking up the token. If the token is valid, it is likely useful to set a property on the request object indicating that so that your routes can check it later, e.g. req.authenticated = true or req.clientId = lookupClientIdFrom(token).

Resource Owner Password Credentials Hooks

The idea behind this OAuth 2 flow is that your API clients will prompt the user for their username and password, and send those to your API in exchange for an access token. This has some advantages over simply sending the user's credentials to the server directly. For example, it obviates the need for the client to store the credentials, and allows expiration and revocation of tokens. However, it does imply that you trust your API clients, since they will have at least one-time access to the user's credentials.

To install Restify–OAuth2's resource owner password credentials flow into your infrastructure, you will need to provide it with the following hooks in the options.hooks hash. You can see some example ROPC hooks in the demo application.

validateClient({ clientId, clientSecret }, req, cb)

Checks that the API client is authorized to use your API, and has the correct secret. It should call back with true or false depending on the result of the check. It can also call back with an error if there was some internal server error while doing the check.

grantUserToken({ clientId, clientSecret, username, password }, req, cb)

Checks that the API client is authenticating on behalf of a real user with correct credentials. It should call back with a new token for that user if so, or false if the credentials are incorrect. It can also call back with an error if there was some internal server error while validating the credentials.

authenticateToken(token, req, cb)

Checks that a token is valid, i.e. that it was granted in the past by grantUserToken. It should call back with true if so, or false if the token is invalid. It can also call back with an error if there was some internal server error while looking up the token. If the token is valid, it is likely useful to set a property on the request object indicating that so that your routes can check it later, e.g. req.authenticated = true or req.username = lookupUsernameFrom(token).

Scope-Granting Hook

Optionally, it is possible to limit the scope of the issued tokens, so that you can implement an authorization system in your application in addition to simple authentication.

grantScopes(credentials, scopesRequested, req, cb)

This hook is called after the token has been granted by authenticateToken. In the client credentials flow, credentials will be { clientId, clientSecret, token }; in the resource owner password credentials flow, it will be { clientId, clientSecret, username, password, token }. In both cases, scopesRequested will be an array of the requested scopes.

This hook can respond in several ways:

  • It can call back with true to grant all of the requested scopes.
  • It can call back with false to indicate that the requested scopes are invalid, unknown, or exceed the set of scopes that should be granted to the given credentials.
  • It can call back with an array to grant a different set of scopes.
  • It can call back with an error if there was some internal server error while granting scopes.

In the cases of false or an internal server error, you should probably revoke the token before calling back, as the server will send the user an error response, instead of a successful token grant.

Other Options

The hooks hash is the only required option, but the following are also available for tweaking:

  • tokenEndpoint: the location at which the token endpoint should be created. Defaults to "/token".
  • wwwAuthenticateRealm: the value of the "Realm" challenge in the WWW-Authenticate header. Defaults to "Who goes there?".
  • tokenExpirationTime: the value returned for the expires_in component of the response from the token endpoint. Note that this is only the value reported; you are responsible for keeping track of token expiration yourself and calling back with false from authenticateToken when the token expires. Defaults to Infinity.

What Does That Look Like?

OK, let's try something a bit more concrete. If you check out the example servers used in the integration tests, you'll see our setup. Here we'll walk you through the more complicated resource owner password credentials example, but the idea for the client credentials example is very similar.

/

The initial resource, at which people enter the server.

  • If a valid token is supplied in the Authorization header, req.username is truthy, and the app responds with links to /public and /secret.
  • If no token is supplied, the app responds with links to /token and /public.
  • If an invalid token is supplied, Restify–OAuth2 intercepts the request before it gets to the application, and sends an appropriate 400 or 401 error.

/token

The token endpoint, managed entirely by Restify–OAuth2. It generates tokens for a given client ID/client secret/username/password combination.

The client validation and token-generation logic is provided by the application, but none of the ceremony necessary for OAuth 2 conformance, error handling, etc. is present in the application code: Restify–OAuth2 takes care of all of that.

/public

A public resource anyone can access.

  • If a valid token is supplied in the Authorization header, req.username contains the username, and the app uses that to send a personalized response.
  • If no token is supplied, req.username is null. The app still sends a response, just without personalizing.
  • If an invalid token is supplied, Restify–OAuth2 intercepts the request before it gets to the application, and sends an appropriate 400 or 401 error.

/secret

A secret resource that only authenticated users can access.

  • If a valid token is supplied in the Authorization header, req.username is truthy, and the app sends the secret data.
  • If no token is supplied, req.username is null, so the application uses res.sendUnauthenticated() to send a nice 401 error with WWW-Authenticate and Link headers.
  • If an invalid token is supplied, Restify–OAuth2 intercepts the request before it gets to the application, and sends an appropriate 400 or 401 error.

More Repositories

1

chai-as-promised

Extends Chai with assertions about promises.
JavaScript
1,417
star
2

promises-unwrapping

The ES6 promises spec, as per September 2013 TC39 meeting
JavaScript
1,219
star
3

sinon-chai

Extends Chai with assertions for the Sinon.JS mocking framework.
JavaScript
1,087
star
4

svg2png

Converts SVGs to PNGs, using PhantomJS
JavaScript
573
star
5

count-to-6

An intro to some ES6 features via a set of self-guided workshops.
JavaScript
326
star
6

opener

Opens stuff, like webpages and files and executables, cross-platform
JavaScript
293
star
7

html-as-custom-elements

HTML as Custom Elements
CSS
260
star
8

proposal-blocks

Former home of a proposal for a new syntactic construct for serializable blocks of JavaScript code
215
star
9

zones

Former home of the zones proposal for JavaScript
204
star
10

worm-scraper

Scrapes the web serial Worm and its sequel Ward into an eBook format
JavaScript
179
star
11

jadeify

A simple browserify transform for turning .jade files into template functions
JavaScript
162
star
12

mocha-as-promised

Adds “thenable” promise support to the Mocha test runner.
JavaScript
132
star
13

especially

Abstract operations and other functions drawn from the ECMAScript specification
JavaScript
91
star
14

dict

A lightweight but safe dictionary, for when Object won't cut it
CoffeeScript
75
star
15

infinite-list-study-group

Moved to WICG/virtual-scroller
72
star
16

understanding-node

Material for the "Understanding the Node.js Platform" class at General Assembly
JavaScript
66
star
17

promise-tests

DEPRECATED: use https://github.com/promises-aplus/promises-tests instead!
JavaScript
61
star
18

proposal-arraybuffer-transfer

Former home of the now-withdrawn ArrayBuffer.prototype.transfer() proposal for JavaScript
60
star
19

path-is-inside

Tests whether one path is inside another path
JavaScript
40
star
20

streams-demo

Demo for Fetch + Streams
HTML
40
star
21

sorted-object

Returns a copy of an object with its keys sorted
JavaScript
35
star
22

traceur-runner

Runs JavaScript.next code in Node by compiling it with Traceur on the fly, seamlessly
JavaScript
35
star
23

last

A small helper for getting only the latest result of an asynchronous operation you perform multiple times in a row.
JavaScript
31
star
24

get-originals

A web platform API that allows access to the "original" versions of the global built-in objects' properties and methods
28
star
25

webidl-class-generator

Generates classes from WebIDL plus implementation code
JavaScript
28
star
26

pubit

Responsible publish/subscribe. Hide the event publisher, only exposing the event emitter.
CoffeeScript
28
star
27

browserify-deoptimizer

Transforms browserify bundles into a collection of single files
CoffeeScript
26
star
28

unhandled-rejections-browser-spec

Spec patches for HTML and ES for tracking unhandled promise rejections with events
22
star
29

wpt-runner

Runs web platform tests in Node.js using jsdom
JavaScript
21
star
30

template-parts

Brainstorming a <template> parts proposal
20
star
31

cooperatively-sized-iframes

A proposal for iframes which can resize according to their content
19
star
32

client-side-packages-demo

A demo application that shows recent commits to npm, using npm packages on the client side via browserify
JavaScript
18
star
33

es6isnigh

A presentation on the future of the JavaScript language.
JavaScript
17
star
34

specgo

A command-line tool for opening web specifications
JavaScript
16
star
35

element-constructors

Some ideas for how to implement constructors for Element, HTMLElement, etc.
JavaScript
15
star
36

html-dashboard

A dashboard for issue and pull request management in whatwg/html
JavaScript
14
star
37

dynamo-as-promised

A promise-based client for Amazon's DynamoDB.
CoffeeScript
11
star
38

amd-wrap

Wraps CommonJS files in `define(function (require, exports, module) { ... })`.
JavaScript
11
star
39

domains-tragedy

An illustration of how Node.js domains can fail you when EventEmitters get involved.
JavaScript
10
star
40

rewrapper

A web application for rewrapping text to fit a column limit
HTML
9
star
41

chromiumizer

Convert an image into the Chromium color pallette
JavaScript
9
star
42

webidl-html-reflector

Implements the algorithms to reflect HTML content attributes as WebIDL attributes
JavaScript
8
star
43

grunt-amd-wrap

Grunt task to wrap CommonJS files in `define(function (require, exports, module) { ... })`.
JavaScript
8
star
44

extensions

Useful extension methods from my own projects
C#
8
star
45

remember-to-eat

My personal meal/calorie/protein tracker
JavaScript
6
star
46

global-wrap

Exposes your CommonJS-based libraries as a global.
JavaScript
6
star
47

origin-agent-cluster-demo.dev

Some Origin-Agent-Cluster demos
HTML
6
star
48

v8-extras-geometry

An exploration of using V8 extras to implement the Geometry spec
JavaScript
6
star
49

jake-diagram-generator

Generates "Jake diagrams", i.e. browser session history timeline diagrams
JavaScript
6
star
50

blog.domenic.me

Hidden Variables: my infrequently-updated blog
Nunjucks
6
star
51

eslint-config

My personal base ESLint config
JavaScript
6
star
52

jsdom-proxy-benchmark

Benchmark for proxies that uses jsdom to build the ECMAScript spec
JavaScript
6
star
53

unownbot-filtered

A daemon that will filter @UnownBot to specific areas and text you about it
JavaScript
6
star
54

cs4h

Homework for General Assembly's CS for Hackers course (Summer 2012)
JavaScript
5
star
55

wk-scripts

My userscripts for WaniKani
JavaScript
4
star
56

gmify

A simple interface to GraphicsMagick for streaming image processing.
JavaScript
4
star
57

emu-algify

Use Ecmarkup's <emu-alg> elements in your HTML
JavaScript
3
star
58

warmup-reps

Initial work on an algorithmically-sound warmup rep calculator
JavaScript
3
star
59

grunt-global-wrap

Grunt task to expose your CommonJS-based libraries as a global.
JavaScript
3
star
60

domains-romance

An illustration of how domains can catch errors on your Node.js server
JavaScript
3
star
61

corrigibility

Corrigibility with Utility Preservation, in TypeScript
TypeScript
3
star
62

throw-catch-cancel-syntax

SweetJS macros for throw cancel and catch cancel
JavaScript
2
star
63

streaming-mediastreams

A spec for extracting the contents of a MediaStream object as a ReadableStream
Shell
2
star
64

whatwg-participant-data-test

A dumping ground test repository for developing whatwg/participate.whatwg.org
1
star
65

test262-to-mjsunit

Converts test262 tests to mjsunit tests
JavaScript
1
star
66

baseline-tester

Runs a function against given inputs and tests the result against baseline outputs
JavaScript
1
star
67

pidgey-calc

A progressive web app that calculates how many Pidgeys you need for your next evolution spree in in Pokémon Go.
HTML
1
star