platform/packages/auth_oauth2
thomashii@dukefirehawk.com 1560e147cc Updated min SDK to 2.17
2022-08-13 10:14:43 +08:00
..
example Updated to SDK 2.16.x 2022-04-23 12:21:39 +08:00
lib Published oauth2, cache, cors, auth_oauth2 2021-05-30 08:46:13 +08:00
.gitignore Add 'packages/auth_oauth2/' from commit '97bd61e7ee6736c8a871d6cc45a5203e07bb03e6' 2020-02-15 18:28:54 -05:00
analysis_options.yaml Updated auth 2021-09-29 15:40:27 +08:00
AUTHORS.md Published oauth2, cache, cors, auth_oauth2 2021-05-30 08:46:13 +08:00
CHANGELOG.md Updated to SDK 2.16.x 2022-04-23 12:21:39 +08:00
LICENSE Updated auth 2021-09-29 15:40:27 +08:00
melos_angel3_auth_oauth2.iml Added melos 2022-03-19 09:37:28 +08:00
pubspec.yaml Updated min SDK to 2.17 2022-08-13 10:14:43 +08:00
README.md Fixed requireAuthentication 2021-10-04 13:13:56 +08:00

Angel3 OAuth2 Handler

Pub Version (including pre-releases) Null Safety(https://dart.dev/null-safety) Gitter License

Angel3 library for authenticating users with remote identity providers via OAuth2, i.e. Facebook, Google, Azure AD, etc.

Usage

First, create an options object:

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

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

typedef OAuth2Verifier = FutureOr<User> Function(oauth2.Client, RequestContext, ResponseContext);

/// You might use a pure function to create a verifier that queries a
/// given service.
OAuth2Verifier oauth2verifier(Service<User> userService) {
  return (client) async {
     var response = await client.get('https://api.github.com/user');
      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));
      }
   };
}

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

configureServer(Angel app) {
  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();
    },
  );
}

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

  1. Redirect users to the external provider
  2. Acts as a callback and handles an access code

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:

configureServer(Angel app) async {
  // ...
  var auth = AngelAuth<User>();
  auth.strategies['github'] = oauth2Strategy;
  
  // Redirect
  app.get('/auth/github', auth.authenticate('github'));
  
  // Callback
  app.get('/auth/github/callback', auth.authenticate(
    'github',
    AngelAuthOptions(callback: confirmPopupAuthentication())
  ));
  
  // Connect the plug-in!!!
  await app.configure(auth);
}

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:

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

Handling non-JSON responses

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:

OAuth2Strategy(
    // ...
    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);
      }

      throw FormatException('Invalid content-type $contentType; expected application/x-www-form-urlencoded or application/json.');
    }
);