oauth2_custom_uri_scheme 0.4.7

Flutter Android iOS

An implementation of OAuth 2.0 authorization code grant with redirection to application specific custom URL scheme.

IMPORTANT NOTE #

oauth2_custom_uri_scheme #

An implementation of OAuth 2.0 Authorization Code Grant with redirection to application specific custom URI scheme.

To make the implementation safer (but not perfect), it implements the following features:

The implementation works well on Android with API level >= 23 and iOS >= 11.0 but it even runs on older API/OS versions.

Installation #

dependencies:
  oauth2_custom_uri_scheme: ^0.4.7

Getting Started #

import 'package:oauth2_custom_uri_scheme/oauth2_custom_uri_scheme.dart';
import 'package:oauth2_custom_uri_scheme/oauth2_token_holder.dart';

...

//
// OAuth2Config can be app global to keep the OAuth configuration
//
final oauth2Config = OAuth2Config(
  uniqueId: 'example.com#1', // NOTE: ID to identify the credential for box session
  authorizationEndpoint: Uri.parse('https://example.com/authorize'),
  tokenEndpoint: Uri.parse('https://example.com/token'),
  // revocationEndpoint is optional
  revocationEndpoint: Uri.parse('https://example.com/revoke'),
  // NOTE: For Android, we also have corresponding intent-filter entry on example/android/app/src/main/AndroidManifest.xml
  redirectUri: Uri.parse('com.example.redirect43763246328://callback'),
  clientId: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
  clientSecret: 'yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy',
  // scope: 'profile',
  useBasicAuth: false);

...

Widget build(BuildContext context) {
  return Scaffold(
    appBar: AppBar(
      title: Text('Simple OAuth Sample'),
    ),
    body: Center(
      // OAuth2TokenHolder is the easiest way to create [authorize] button.
      child: OAuth2TokenHolder(
        config: oauth2Config,
        builder: (context, accessToken, state, authorize, deauthorize, child) => ListTile(title: RaisedButton(
          onPressed:() => accessToken == null ? authorize() : deauthorize(),
          child: state == OAuth2TokenAvailability.Authorizing
          ? const CircularProgressIndicator()
          : Text(accessToken == null ? 'Authorize' : 'Deauthorize'))
        )
      )
    )
  );
}

// After [Authorize] on the UI, we can get the access token from cache.
AccessToken token = await oauth2Config.getAccessTokenFromCache();

// Or, of course, you can authorize the app
// If reset=false, it may use the cache and the method returns immediately;
// otherwise reset=true, it always tries to authorize the app.
AccessToken token = await oauth2Config.authorize(reset: true);

// OK, we can execute GET query
final foobarResult = await token.getJsonFromUri('https://example.com/api/2.0/foobar');

Lower level API #

To use the plugin with your OAuth service provider, call AccessToken.authorize with your OAuth service's endpoints and client configuration:

final AccessToken token = await AccessToken.authorize(
    authorizationEndpoint: Uri.parse('https://example.com/authorize'),
    tokenEndpoint: Uri.parse('https://example.com/token'),
    // NOTE: For Android, we also have corresponding intent-filter entry on example/android/app/src/main/AndroidManifest.xml
    redirectUri: Uri.parse('com.example.redirect43763246328://callback'),
    clientId: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
    clientSecret: 'yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy',
    useBasicAuth: false, // certain services such as Box does not support Basic Auth
    idForCache: 'example.com#1' // used when caching access token
);
if (token == null) {
    // error handling
}

// OK, we can execute GET query
final foobarResult = await token.getJsonFromUri('https://example.com/api/2.0/foobar');

// POST query
final request = await token.createRequest('POST', 'https://example.com/api/2.0/zzzzz');
request.body = '....';
final response = await request.send();

Additional settings on Android #

For Android, we should update several configurations:

We should add AndroidManifest.xml to include additional <intent-filter> under <activity>.

<intent-filter>
    <action android:name="android.intent.action.VIEW" />
    <category android:name="android.intent.category.DEFAULT" />
    <category android:name="android.intent.category.BROWSABLE" />
    <!-- Should match to the one on example/lib/main.dart -->
    <data android:scheme="com.example.redirect43763246328" android:host="callback" />
</intent-filter>

API reference #

API reference on pub.dev.

Security considerations #

On every platform, we can define a custom URI scheme to launch our app on URI redirects.

Although the URI may be something like myapp://localhost, the URI scheme here, myapp is not suitable for accepting authorization code redirect. If any other apps may use the same URI scheme, the authorization code may be intercepted by them without launching our app.

Basically, it's almost impossible to hide our custom URI scheme from others, apparently, we should choose one carefully not to conflict with other apps.

At least, we should use app scheme like com.example.mwl5oodcb9, which contains some random characters (but they should be lowercase anyway).

To reduce the risk of others intercepting authorization code, the plugin implements RFC 7636: Proof Key for Code Exchange (PKCE) by OAuth Public Clients. But not every OAuth service implements it.

2
likes
90
pub points
54%
popularity

Publisher

espresso3389.jp

An implementation of OAuth 2.0 authorization code grant with redirection to application specific custom URL scheme.

Repository (GitHub)
View/report issues

Documentation

API reference

License

MIT (LICENSE)

Dependencies

crypto, flutter, flutter_inappwebview, flutter_secure_storage, http, reader_writer_lock, rxdart

More

Packages that depend on oauth2_custom_uri_scheme