1
0
Fork 0
arangodb/Documentation/Books/Manual/Foxx/OAuth2.mdpp

270 lines
9.5 KiB
Plaintext

OAuth 2.0
=========
`const createOAuth2Client = require('@arangodb/foxx/oauth2');`
The OAuth2 module provides abstractions over OAuth 2.0 providers like Facebook, GitHub and Google.
**Examples**
The following extends the [user management example](Users.md):
```js
const crypto = require('@arangodb/crypto');
const router = createRouter();
const oauth2 = createOAuth2Client({
// We'll use Facebook for this example
authEndpoint: 'https://www.facebook.com/dialog/oauth',
tokenEndpoint: 'https://graph.facebook.com/oauth/access_token',
activeUserEndpoint: 'https://graph.facebook.com/v2.0/me',
clientId: 'keyboardcat',
clientSecret: 'keyboardcat'
});
module.context.use('/oauth2', router);
// See the user management example for setting up the
// sessions and users objects used in this example
router.use(sessions);
router.post('/auth', function (req, res) {
const csrfToken = crypto.genRandomAlphaNumbers(32);
const url = req.reverse('oauth2_callback', {csrfToken});
const redirect_uri = req.makeAbsolute(url);
// Set CSRF cookie for five minutes
res.cookie('oauth2_csrf_token', csrfToken, {ttl: 60 * 5});
// Redirect to the provider's authorization URL
res.redirect(303, oauth2.getAuthUrl(redirect_uri));
});
router.get('/auth', function (req, res) {
// Some providers pass errors as query parameter
if (req.queryParams.error) {
res.throw(500, `Provider error: ${req.queryParams.error}`)
}
// Make sure CSRF cookie matches the URL
const expectedToken = req.cookie('oauth2_csrf_token');
if (!expectedToken || req.queryParams.csrfToken !== expectedToken) {
res.throw(400, 'CSRF mismatch.');
}
// Make sure the URL contains a grant token
if (!req.queryParams.code) {
res.throw(400, 'Provider did not pass grant token.');
}
// Reconstruct the redirect_uri used for the grant token
const url = req.reverse('oauth2_callback');
const redirect_uri = req.makeAbsolute(url);
// Fetch an access token from the provider
const authData = oauth2.exchangeGrantToken(
req.queryParams.code,
redirect_uri
);
const facebookToken = authData.access_token;
// Fetch the active user's profile info
const profile = oauth2.fetchActiveUser(facebookToken);
const facebookId = profile.id;
// Try to find an existing user with the user ID
// (this requires the users collection)
let user = users.firstExample({facebookId});
if (user) {
// Update the facebookToken if it has changed
if (user.facebookToken !== facebookToken) {
users.update(user, {facebookToken});
}
} else {
// Create a new user document
user = {
username: `fb:${facebookId}`,
facebookId,
facebookToken
}
const meta = users.save(user);
Object.assign(user, meta);
}
// Log the user in (this requires the session middleware)
req.session.uid = user._key;
req.session.facebookToken = authData.facebookToken;
req.sessionStorage.save(req.session);
// Redirect to the default route
res.redirect(303, req.makeAbsolute('/'));
}, 'oauth2_callback')
.queryParam('error', joi.string().optional())
.queryParam('csrfToken', joi.string().optional())
.queryParam('code', joi.string().optional());
```
Creating an OAuth 2.0 client
-------------------------
`createOAuth2Client(options): OAuth2Client`
Creates an OAuth 2.0 client.
**Arguments**
* **options**: `Object`
An object with the following properties:
* **authEndpoint**: `string`
The fully-qualified URL of the provider's [authorization endpoint](http://tools.ietf.org/html/rfc6749#section-3.1).
* **tokenEndpoint**: `string`
The fully-qualified URL of the provider's [token endpoint](http://tools.ietf.org/html/rfc6749#section-3.2).
* **refreshEndpoint**: `string` (optional)
The fully-qualified URL of the provider's [refresh token endpoint](http://tools.ietf.org/html/rfc6749#section-6).
* **activeUserEndpoint**: `string` (optional)
The fully-qualified URL of the provider's endpoint for fetching details about the current user.
* **clientId**: `string`
The application's *Client ID* (or *App ID*) for the provider.
* **clientSecret**: `string`
The application's *Client Secret* (or *App Secret*) for the provider.
Returns an OAuth 2.0 client for the given provider.
### Setting up OAuth 2.0 for Facebook
If you want to use Facebook as the OAuth 2.0 provider, use the following options:
* *authEndpoint*: `https://www.facebook.com/dialog/oauth`
* *tokenEndpoint*: `https://graph.facebook.com/oauth/access_token`
* *activeUserEndpoint*: `https://graph.facebook.com/v2.0/me`
You also need to obtain a client ID and client secret from Facebook:
1. Create a regular account at [Facebook](https://www.facebook.com) or use an existing account you own.
2. Visit the [Facebook Developers](https://developers.facebook.com) page.
3. Click on *Apps* in the menu, then select *Register as a Developer* (the only option) and follow the instructions provided. You may need to verify your account by phone.
4. Click on *Apps* in the menu, then select *Create a New App* and follow the instructions provided.
5. Open the app dashboard, then note down the *App ID* and *App Secret*. The secret may be hidden by default.
6. Click on *Settings*, then *Advanced* and enter one or more *Valid OAuth redirect URIs*. At least one of them must match your *redirect_uri* later. Don't forget to save your changes.
7. Set the option *clientId* to the *App ID* and the option *clientSecret* to the *App Secret*.
### Setting up OAuth 2.0 for GitHub
If you want to use GitHub as the OAuth 2.0 provider, use the following options:
* *authEndpoint*: `https://github.com/login/oauth/authorize?scope=user`
* *tokenEndpoint*: `https://github.com/login/oauth/access_token`
* *activeUserEndpoint*: `https://api.github.com/user`
You also need to obtain a client ID and client secret from GitHub:
1. Create a regular account at [GitHub](https://github.com) or use an existing account you own.
2. Go to [Account Settings > Applications > Register new application](https://github.com/settings/applications/new).
3. Provide an *authorization callback URL*. This must match your *redirect_uri* later.
4. Fill in the other required details and follow the instructions provided.
5. Open the application page, then note down the *Client ID* and *Client Secret*.
6. Set the option *clientId* to the *Client ID* and the option *clientSecret* to the *Client Secret*.
### Setting up OAuth 2.0 for Google
If you want to use Google as the OAuth 2.0 provider, use the following options:
* *authEndpoint*: `https://accounts.google.com/o/oauth2/auth?access_type=offline&scope=profile`
* *tokenEndpoint*: `https://accounts.google.com/o/oauth2/token`
* *activeUserEndpoint*: `https://www.googleapis.com/plus/v1/people/me`
You also need to obtain a client ID and client secret from Google:
1. Create a regular account at [Google](https://www.google.com) or use an existing account you own.
2. Visit the [Google Developers Console](https://console.developers.google.com).
3. Click on *Create Project*, then follow the instructions provided.
4. When your project is ready, open the project dashboard, then click on *Enable an API*.
5. Enable the *Google+ API* to allow your app to distinguish between different users.
6. Open the *Credentials* page and click *Create new Client ID*, then follow the instructions provided. At least one *Authorized Redirect URI* must match your *redirect_uri* later. At least one *Authorized JavaScript Origin* must match your app's fully-qualified domain.
7. When the Client ID is ready, note down the *Client ID* and *Client secret*.
8. Set the option *clientId* to the *Client ID* and the option *clientSecret* to the *Client secret*.
Get the authorization URL
-------------------------
`oauth2.getAuthUrl(redirect_uri, args): string`
Generates the authorization URL for the authorization endpoint.
**Arguments**
* **redirect_uri**: `string`
The fully-qualified URL of your application's OAuth 2.0 callback.
* **args**: (optional)
An object with any of the following properties:
* **response_type**: `string` (Default: `"code"`)
See [RFC 6749](http://tools.ietf.org/html/rfc6749).
Returns a fully-qualified URL for the authorization endpoint of the provider by appending the client ID and any additional arguments from *args* to the *authEndpoint*.
Exchange a grant code for an access token
-----------------------------------------
`oauth2.exchangeGrantToken(code, redirect_uri)`
Exchanges a grant code for an access token.
Performs a *POST* response to the *tokenEndpoint*.
Throws an exception if the remote server responds with an empty response body.
**Arguments**
* **code**: `string`
A grant code returned by the provider's authorization endpoint.
* **redirect_uri**: `string`
The original callback URL with which the code was requested.
* **args**: `Object` (optional)
An object with any of the following properties:
* **grant_type**: `string` (Default: `"authorization_code"`)
See [RFC 6749](http://tools.ietf.org/html/rfc6749).
Returns the parsed response object.
Fetch the active user
---------------------
`oauth2.fetchActiveUser(access_token): Object`
Fetches details of the active user.
Performs a *GET* response to the *activeUserEndpoint*.
Throws an exception if the remote server responds with an empty response body.
Returns `null` if the *activeUserEndpoint* is not configured.
**Arguments**
* **access_token**: `string`
An OAuth 2.0 access token as returned by *exchangeGrantToken*.
Returns the parsed response object.
**Examples**
```js
const authData = oauth2.exchangeGrantToken(code, redirect_uri);
const userData = oauth2.fetchActiveUser(authData.access_token);
```