auth_oauth2

Pub

package:angel_auth strategy for OAuth2 login, i.e. Facebook or Github.

Usage

First, create an options object:

  1. configureServer(Angel app) async {
  2. // Load from a Map, i.e. app config:
  3. var opts = ExternalAuthOptions.fromMap(app.configuration['auth0'] as Map);
  4.  
  5. // Create in-place:
  6. var opts = ExternalAuthOptions(
  7. clientId: '<client-id>',
  8. clientSecret: '<client-secret>',
  9. redirectUri: Uri.parse('<callback>'));
  10. }

After getting authenticated against the remote server, we need to be able to identifyusers within our own application.

  1. typedef FutureOr<User> OAuth2Verifier(oauth2.Client, RequestContext, ResponseContext);
  2.  
  3. /// You might use a pure function to create a verifier that queries a
  4. /// given service.
  5. OAuth2Verifier oauth2verifier(Service<User> userService) {
  6. return (client) async {
  7. var response = await client.get('https://api.github.com/user');
  8. var ghUser = json.decode(response.body);
  9. var id = ghUser['id'] as int;
  10.  
  11. var matchingUsers = await mappedUserService.index({
  12. 'query': {'github_id': id}
  13. });
  14.  
  15. if (matchingUsers.isNotEmpty) {
  16. // Return the corresponding user, if it exists.
  17. return matchingUsers.first;
  18. } else {
  19. // Otherwise,create a user
  20. return await mappedUserService.create(User(githubId: id));
  21. }
  22. };
  23. }

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).

  1. configureServer(Angel app) {
  2. auth.strategies['github'] = OAuth2Strategy(
  3. options,
  4. authorizationEndpoint,
  5. tokenEndpoint,
  6. yourVerifier,
  7.  
  8. // This function is called when an error occurs, or the user REJECTS the request.
  9. (e, req, res) async {
  10. res.write('Ooops: $e');
  11. await res.close();
  12. },
  13. );
  14. }

Lastly, connect it to an AngelAuth instance, and wire it up to an Angel server.Set up two routes:

  • Redirect users to the external provider
  • Acts as a callback and handles an access codeIn the case of the callback route, you may want to display an HTML page that closesa popup window. In this case, use confirmPopupAuthentication, which is bundled withpackage:angel_auth, as a callback function:
  1. configureServer(Angel app) async {
  2. // ...
  3. var auth = AngelAuth<User>();
  4. auth.strategies['github'] = oauth2Strategy;
  5.  
  6. // Redirect
  7. app.get('/auth/github', auth.authenticate('github'));
  8.  
  9. // Callback
  10. app.get('/auth/github/callback', auth.authenticate(
  11. 'github',
  12. AngelAuthOptions(callback: confirmPopupAuthentication())
  13. ));
  14.  
  15. // Connect the plug-in!!!
  16. await app.configure(auth);
  17. }

Custom Scope Delimiter

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:

  1. configureServer(Angel app) async {
  2. OAuth2Strategy(..., delimiter: ' ');
  3. }

Handling non-JSON responses

Many OAuth2 providers do not follow the specification, and do not returnapplication/json responses.

You can add a getParameters callback to parse the contents of any arbitraryresponse:

  1. OAuth2Strategy(
  2. // ...
  3. getParameters: (contentType, body) {
  4. if (contentType.type == 'application') {
  5. if (contentType.subtype == 'x-www-form-urlencoded')
  6. return Uri.splitQueryString(body);
  7. else if (contentType.subtype == 'json') return JSON.decode(body);
  8. }
  9.  
  10. throw FormatException('Invalid content-type $contentType; expected application/x-www-form-urlencoded or application/json.');
  11. }
  12. );