2024-10-12 10:35:14 +00:00
# Protevus OAuth2 Handler
2021-07-10 01:29:41 +00:00
2021-09-29 07:40:27 +00:00
![Pub Version (including pre-releases) ](https://img.shields.io/pub/v/angel3_auth_oauth2?include_prereleases )
2021-10-04 05:13:56 +00:00
![Null Safety ](https://img.shields.io/badge/null-safety-brightgreen )(< https: // dart . dev / null-safety > )
2024-07-07 15:02:49 +00:00
[![Discord ](https://img.shields.io/discord/1060322353214660698 )](https://discord.gg/3X6bxTUdCM)
2024-10-12 10:35:14 +00:00
[![License ](https://img.shields.io/github/license/dart-backend/protevus )](https://github.com/dart-backend/protevus/tree/master/packages/auth_oauth2/LICENSE)
2017-01-12 22:48:51 +00:00
2024-10-12 10:35:14 +00:00
Protevus library for authenticating users with remote identity providers via OAuth2, i.e. Facebook, Google, Azure AD, etc.
2021-07-10 01:29:41 +00:00
## Usage
2017-06-03 21:05:13 +00:00
First, create an options object:
```dart
configureServer(Angel app) async {
// Load from a Map, i.e. app config:
2019-01-06 00:43:06 +00:00
var opts = ExternalAuthOptions.fromMap(app.configuration['auth0'] as Map);
2017-06-03 21:05:13 +00:00
// Create in-place:
2019-01-06 00:43:06 +00:00
var opts = ExternalAuthOptions(
clientId: '< client-id > ',
clientSecret: '< client-secret > ',
redirectUri: Uri.parse('< callback > '));
2017-06-03 21:05:13 +00:00
}
```
2021-07-10 01:29:41 +00:00
After getting authenticated against the remote server, we need to be able to identify users within our own application.
2017-06-03 21:05:13 +00:00
```dart
2021-07-10 01:29:41 +00:00
typedef OAuth2Verifier = FutureOr< User > Function(oauth2.Client, RequestContext, ResponseContext);
2019-01-06 00:43:06 +00:00
2017-06-03 21:05:13 +00:00
/// You might use a pure function to create a verifier that queries a
/// given service.
2019-01-06 00:43:06 +00:00
OAuth2Verifier oauth2verifier(Service< User > userService) {
return (client) async {
2017-06-03 21:05:13 +00:00
var response = await client.get('https://api.github.com/user');
2019-01-06 00:43:06 +00:00
var ghUser = json.decode(response.body);
var id = ghUser['id'] as int;
var matchingUsers = await mappedUserService.index({
'query': {'github_id': id}
});
if (matchingUsers.isNotEmpty) {
// Return the corresponding user, if it exists.
return matchingUsers.first;
} else {
// Otherwise,create a user
return await mappedUserService.create(User(githubId: id));
}
2017-06-03 21:05:13 +00:00
};
}
```
2021-07-10 01:29:41 +00:00
Now, initialize an `OAuth2Strategy` , using the options and verifier. You'll also need to provide a name for this instance of the strategy. Consider using the name of the remote authentication provider (ex. `facebook` ).
2017-06-03 21:05:13 +00:00
```dart
configureServer(Angel app) {
2019-01-06 00:43:06 +00:00
auth.strategies['github'] = OAuth2Strategy(
options,
authorizationEndpoint,
tokenEndpoint,
yourVerifier,
// This function is called when an error occurs, or the user REJECTS the request.
(e, req, res) async {
res.write('Ooops: $e');
await res.close();
},
);
2017-06-03 21:05:13 +00:00
}
```
2021-07-10 01:29:41 +00:00
Lastly, connect it to an `AngelAuth` instance, and wire it up to an `Angel` server. Set up two routes:
2017-06-03 21:05:13 +00:00
1. Redirect users to the external provider
2. Acts as a callback and handles an access code
2021-07-10 01:29:41 +00:00
In the case of the callback route, you may want to display an HTML page that closes a popup window. In this case, use `confirmPopupAuthentication` , which is bundled with `package:angel3_auth` , as a `callback` function:
2017-06-03 21:05:13 +00:00
```dart
configureServer(Angel app) async {
// ...
2019-01-06 00:43:06 +00:00
var auth = AngelAuth< User > ();
2018-09-12 03:23:42 +00:00
auth.strategies['github'] = oauth2Strategy;
2017-06-03 21:05:13 +00:00
// Redirect
app.get('/auth/github', auth.authenticate('github'));
// Callback
app.get('/auth/github/callback', auth.authenticate(
'github',
2019-01-06 00:43:06 +00:00
AngelAuthOptions(callback: confirmPopupAuthentication())
2017-06-03 21:05:13 +00:00
));
// Connect the plug-in!!!
await app.configure(auth);
}
```
## Custom Scope Delimiter
2021-07-10 01:29:41 +00:00
This package should work out-of-the-box for most OAuth2 providers, such as Github or Dropbox. However, if your OAuth2 scopes are separated by a delimiter other than the default (`' '`), you can add it in the `OAuth2Strategy` constructor:
2017-06-03 21:05:13 +00:00
```dart
configureServer(Angel app) async {
2019-01-06 00:43:06 +00:00
OAuth2Strategy(..., delimiter: ' ');
2017-06-03 21:05:13 +00:00
}
2018-03-30 16:44:15 +00:00
```
## Handling non-JSON responses
2021-07-10 01:29:41 +00:00
Many OAuth2 providers do not follow the specification, and do not return `application/json` responses.
You can add a `getParameters` callback to parse the contents of any arbitrary response:
2018-03-30 16:44:15 +00:00
```dart
2019-01-06 00:43:06 +00:00
OAuth2Strategy(
2018-03-30 16:44:15 +00:00
// ...
getParameters: (contentType, body) {
if (contentType.type == 'application') {
if (contentType.subtype == 'x-www-form-urlencoded')
return Uri.splitQueryString(body);
else if (contentType.subtype == 'json') return JSON.decode(body);
}
2019-01-06 00:43:06 +00:00
throw FormatException('Invalid content-type $contentType; expected application/x-www-form-urlencoded or application/json.');
2018-03-30 16:44:15 +00:00
}
);
2021-07-10 01:29:41 +00:00
```