mirror of https://gitee.com/bigwinds/arangodb
270 lines
9.5 KiB
Plaintext
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);
|
|
```
|