anvil-connect-nodejs
Version:
Anvil Connect JavaScript client for Node.js
363 lines (278 loc) • 10.8 kB
Markdown
# Anvil Connect client for Node.js
[](https://npm.im/anvil-connect-nodejs)
[](https://travis-ci.org/anvilresearch/connect-nodejs)
[Anvil Connect][connect] is a modern authorization server built to authenticate
your users and protect your APIs. It's based on [OAuth 2.0][oauth2] and
[OpenID Connect][oidc].
This library is a low level OpenID Connect and Anvil Connect API client.
Previous versions included Express-specific functions and
middleware. These higher-level functions are being split out into a
[separate library][connect-express].
[oauth2]: http://tools.ietf.org/html/rfc6749
[oidc]: http://openid.net/connect/
[connect]: https://github.com/anvilresearch/connect
[connect-nodejs]: https://github.com/anvilresearch/connect-nodejs
[connect-express]: https://github.com/anvilresearch/connect-express
### Install
```bash
$ npm install anvil-connect-nodejs --save
```
### Configure
Before performing any other operations (such as verifying or refreshing OIDC
tokens, or accessing the AnvilConnect-specific API (such as creating users),
an OIDC client needs to be configured and registered with the server (OIDC
Provider, OP for short).
#### new AnvilConnect(config)
```javascript
var AnvilConnectClient = require('anvil-connect-nodejs');
// If the client has been pre-registered, pass the credentials to constructor
var client = new AnvilConnectClient({
issuer: 'https://connect.example.com',
client_id: 'CLIENT_ID',
client_secret: 'CLIENT_SECRET',
redirect_uri: 'REDIRECT_URI',
scope: 'realm'
})
client.initProvider()
.then(function () {
// Ready to verify() tokens, refresh(), etc
})
// If the client has not been registered, use OIDC dynamic registration
var client = new AnvilConnectClient({ issuer: 'https://connect.example.com' })
client.initProvider()
.then(function () {
// Provider config loaded (.discover() and .getJWKs() called)
// Ready to register()
return client.register({
// ... see below for registration options
})
})
.then(function () {
// Client is now registered. Ready to verify() tokens, refresh(), etc
})
.catch(function (err) {
// as always, don't forget error handling
})
```
**options**
* `issuer` – REQUIRED uri of your OpenID Connect provider
* `client_id` – OPTIONAL client identifier issued by OIDC provider during
registration
* `client_secret` – OPTIONAL confidential value issued by OIDC provider during
registration
* `redirect_uri` – OPTIONAL uri users will be redirected back to after
authenticating with the issuer
* `scope` – OPTIONAL array of strings, or space delimited string value
containing scopes to be included in authorization requests.
Defaults to `openid profile`
### OpenID Connect
#### client.discover()
Returns a promise providing [OpenID Metadata][oidc-meta] retrieved from the
`.well-known/openid-configuration` endpoint for the configured issuer. Sets the
response data as `client.configuration`.
[oidc-meta]: http://openid.net/specs/openid-connect-discovery-1_0.html#ProviderMetadata
**example**
```javascript
client.discover()
.then(function (openidMetadata) {
// client.configuration === openidMetadata
})
.catch(function (error) {
// ...
})
```
#### client.getJWKs()
Returns a promise providing the JWK set published by the configured issuer.
Depends on a prior call to `client.discover()`.
**example**
```javascript
client.getJWKs()
.then(function (jwks) {
// client.jwks === jwks
})
.catch(function (error) {
// ...
})
```
#### client.register(registration)
Dynamically registers a new client with the configured issuer and returns a
promise for the new client registration. You can learn more about [dynamic
registration for Anvil Connect][dynamic-registration] in the docs. Depends on a
prior call to `client.discover()`.
[dynamic-registration]: https://github.com/anvilresearch/connect-docs/blob/master/clients.md#dynamic-registration
**example**
```javascript
var options = {
client_name: 'Antisocial Network',
client_uri: 'https://app.example.com',
logo_uri: 'https://app.example.com/assets/logo.png',
response_types: ['code'],
grant_types: ['authorization_code', 'refresh_token'],
default_max_age: 86400, // one day in seconds
redirect_uris: ['https://app.example.com/callback.html', 'https://app.example.com/other.html'],
post_logout_redirect_uris: ['https://app.example.com']
}
client.register(options)
.then(function (data) {
// After the register request resolves
// client.client_id and .client_secret are initialized
// and the rest of the returned data is set to client.registration
})
```
#### client.authorizationUri([endpoint|options])
Accepts a string specifying a non-default endpoint or an options object and
returns an authorization URI. Depends on a prior call to `client.discover()` and
`client_id` being configured.
**options**
* All options accepted by `client.authorizationParams()`.
* `endpoint` – This value is used for the path in the returned URI. Defaults to `authorize`.
**example**
```javascript
client.authorizationUri()
// 'https://connect.example.com/authorize?response_type=code&client_id=CLIENT_ID&redirect_uri=REDIRECT_URI&scope=openid%20profile%20more'
client.authorizationUri('signin')
// 'https://connect.example.com/signin?response_type=code&client_id=CLIENT_ID&redirect_uri=REDIRECT_URI&scope=openid%20profile%20more'
client.authorizationUri({
endpoint: 'connect/google',
response_type: 'code id_token token',
redirect_uri: 'OTHER_REDIRECT_URI',
scope: 'openid profile extra'
})
// 'https://connect.example.com/connect/google?response_type=code%20id_token%20token&client_id=CLIENT_ID&redirect_uri=OTHER_REDIRECT_URI&scope=openid%20profile%20extra'
```
#### client.authorizationParams(options)
Accepts an options object and returns an object containing authorization params
including default values. Depends on `client_id` being configured.
*Note:* This is a low-level function used by `authorizationUri()`,
documented to list its parameters (which are passed through to
`authorizationParams()`). It's unlikely that your code will be invoking it
directly.
**options**
* `response_type` – defaults to `code`
* `redirect_uri` – defaults to the `redirect_uri` configured for this client
* `scope` – defaults to the scope configured for this client
* `state`
* `response_mode`
* `nonce`
* `display`
* `prompt`
* `max_age`
* `ui_locales`
* `id_token_hint`
* `login_hint`
* `acr_values`
* `email`
* `password`
* `provider`
#### client.token(options)
Given an authorization code is provided as the `code` option, this method will
exchange the auth code for a set of token credentials, then verify the
signatures and decode the payloads. Depends on `client_id` and `client_secret`
being configured, and prior calls to `client.discover()` and `client.getJWKs()`.
**options**
* `code` – value obtained from a successful authorization request with `code`
in the `response_types` request param
**example**
```javascript
client.token({ code: 'AUTHORIZATION_CODE' })
```
#### client.refresh(options)
Given an refresh_token is provided as the `refresh_token` option, this method
will exchange the refresh_token for a set of token credentials, then verify the
signatures. Depends on `client_id` and `client_secret` being configured, and
prior calls to `client.discover()` and `client.getJWKs()`.
**options**
* `refresh_token` – value obtained from a successful authorization request with
`token` in the `response_types` request param
**example**
```javascript
client.refresh({ refresh_token: 'REFRESH_TOKEN' })
```
#### client.userInfo(options)
Get user info from the issuer.
**options**
* `token` – access token
**example**
```javascript
client.userInfo({ token: 'ACCESS_TOKEN' })
```
#### client.verify(token, options)
### Anvil Connect Admin API
Anvil Connect provides a backend admin-only API (outside of the OIDC specs),
for managing clients, users and so on.
Note: All of these operations require an access token passed in `options.token`.
You can get this token either via an admin user (with an `authority` role
assigned to them) login, OR via a Client Credentials Grant request
(see `client.getClientAccessToken()` docs in `../index.js`).
Example Usage:
```
client.getClientAccessToken()
.then(function (accessToken) {
var options = { token: accessToken }
// Once you have the access token you can
// call client.users.update(), create(), delete(), etc
return client.users.create(userData, options)
})
```
#### Clients
#### client.clients.list()
#### client.clients.get(id)
#### client.clients.create(data)
#### client.clients.update(id, data)
#### client.clients.delete(id)
#### Roles
#### client.roles.list()
#### client.roles.get(id)
#### client.roles.create(data)
#### client.roles.update(id, data)
#### client.roles.delete(id)
#### Scopes
#### client.scopes.list()
#### client.scopes.get(id)
#### client.scopes.create(data)
#### client.scopes.update(id, data)
#### client.scopes.delete(id)
#### Users
#### client.users.list()
#### client.users.get(id)
#### client.users.create(data)
#### client.users.update(id, data)
#### client.users.delete(id)
### Example
```javascript
var AnvilConnectClient = require('anvil-connect-nodejs');
// Assumes a preregistered client (if not, call register() after initProvider())
var client = new AnvilConnectClient({
issuer: 'https://connect.example.com',
client_id: 'CLIENT_ID',
client_secret: 'CLIENT_SECRET',
redirect_uri: 'REDIRECT_URI'
})
// Initialize the provider config (endpoints and public keys)
client.initProvider()
.then(function () {
// At this point, provider config and public keys are loaded and cached
console.log(client.configuration)
console.log(jwks)
// Now, build an authorization url
return client.authorizationUri()
})
.then(function (url) {
console.log(url)
// handle an authorization response
// this verifies the signatures on tokens received from the authorization server
return client.token({ code: 'AUTHORIZATION_CODE' })
})
.then(function (tokens) {
// a successful call to tokens() gives us id_token, access_token,
// refresh_token, expiration, and the decoded payloads of the JWTs
console.log(tokens)
// get userinfo
return client.userInfo({ token: tokens.access_token })
})
.then(function (userInfo) {
console.log(userInfo)
// verify an access token received by an API service
return client.verify(JWT, { scope: 'research' })
})
```