diff --git a/openedx/core/djangoapps/oauth_dispatch/migrations/0002_scopedapplication_scopedapplicationorganization.py b/openedx/core/djangoapps/oauth_dispatch/migrations/0002_scopedapplication_scopedapplicationorganization.py
new file mode 100644
index 0000000000000000000000000000000000000000..17e78f09a48171c99b42e31a44f989833e7616cc
--- /dev/null
+++ b/openedx/core/djangoapps/oauth_dispatch/migrations/0002_scopedapplication_scopedapplicationorganization.py
@@ -0,0 +1,46 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.11.13 on 2018-06-20 18:22
+from __future__ import unicode_literals
+
+from django.conf import settings
+from django.db import migrations, models
+import django.db.models.deletion
+import django_mysql.models
+import oauth2_provider.generators
+import oauth2_provider.validators
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        migrations.swappable_dependency(settings.AUTH_USER_MODEL),
+        migrations.swappable_dependency(settings.OAUTH2_PROVIDER_APPLICATION_MODEL),
+        ('oauth_dispatch', '0001_initial'),
+    ]
+
+    operations = [
+        migrations.CreateModel(
+            name='ScopedApplication',
+            fields=[
+                ('client_id', models.CharField(db_index=True, default=oauth2_provider.generators.generate_client_id, max_length=100, unique=True)),
+                ('redirect_uris', models.TextField(blank=True, help_text='Allowed URIs list, space separated', validators=[oauth2_provider.validators.validate_uris])),
+                ('client_type', models.CharField(choices=[('confidential', 'Confidential'), ('public', 'Public')], max_length=32)),
+                ('authorization_grant_type', models.CharField(choices=[('authorization-code', 'Authorization code'), ('implicit', 'Implicit'), ('password', 'Resource owner password-based'), ('client-credentials', 'Client credentials')], max_length=32)),
+                ('client_secret', models.CharField(blank=True, db_index=True, default=oauth2_provider.generators.generate_client_secret, max_length=255)),
+                ('name', models.CharField(blank=True, max_length=255)),
+                ('skip_authorization', models.BooleanField(default=False)),
+                ('id', models.IntegerField(primary_key=True, serialize=False)),
+                ('scopes', django_mysql.models.ListCharField(models.CharField(max_length=32), help_text='Comma-separated list of scopes that this application will be allowed to request.', max_length=825, size=25)),
+                ('user', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='oauth_dispatch_scopedapplication', to=settings.AUTH_USER_MODEL)),
+            ],
+        ),
+        migrations.CreateModel(
+            name='ScopedApplicationOrganization',
+            fields=[
+                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('short_name', models.CharField(help_text='The short_name of an existing Organization.', max_length=255)),
+                ('provider_type', models.CharField(choices=[(b'content_org', 'Content Provider')], default=b'content_org', max_length=32)),
+                ('application', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='organizations', to=settings.OAUTH2_PROVIDER_APPLICATION_MODEL)),
+            ],
+        ),
+    ]
diff --git a/openedx/core/djangoapps/oauth_dispatch/migrations/0003_application_data.py b/openedx/core/djangoapps/oauth_dispatch/migrations/0003_application_data.py
new file mode 100644
index 0000000000000000000000000000000000000000..2727d5960fe697828dab6547a632eb898fd150f3
--- /dev/null
+++ b/openedx/core/djangoapps/oauth_dispatch/migrations/0003_application_data.py
@@ -0,0 +1,40 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.11.13 on 2018-06-05 13:19
+from __future__ import unicode_literals
+
+from django.conf import settings
+from django.db import migrations
+
+
+def migrate_application_data(apps, schema_editor):
+    """
+    Migrate existing DOT Application models to new ScopedApplication models.
+    """
+    Application = apps.get_model(settings.OAUTH2_PROVIDER_APPLICATION_MODEL)
+    ScopedApplication = apps.get_model('oauth_dispatch', 'ScopedApplication')
+
+    for application in Application.objects.all():
+        ScopedApplication.objects.update_or_create(
+            id=application.id,
+            defaults={
+                'client_id': application.client_id,
+                'user': application.user,
+                'redirect_uris': application.redirect_uris,
+                'client_type': application.client_type,
+                'authorization_grant_type': application.authorization_grant_type,
+                'client_secret': application.client_secret,
+                'name': application.name,
+                'skip_authorization': application.skip_authorization,
+            }
+        )
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('oauth_dispatch', '0002_scopedapplication_scopedapplicationorganization'),
+    ]
+
+    operations = [
+        migrations.RunPython(migrate_application_data, reverse_code=migrations.RunPython.noop),
+    ]
diff --git a/openedx/core/djangoapps/oauth_dispatch/models.py b/openedx/core/djangoapps/oauth_dispatch/models.py
index 6c661e36477e7bec13da77c3d23300b09274a2df..0faeb1f0f8a28234c5d3b4fa5d937c0330990150 100644
--- a/openedx/core/djangoapps/oauth_dispatch/models.py
+++ b/openedx/core/djangoapps/oauth_dispatch/models.py
@@ -5,6 +5,9 @@ Specialized models for oauth_dispatch djangoapp
 from datetime import datetime
 
 from django.db import models
+from django.utils.translation import ugettext_lazy as _
+from django_mysql.models import ListCharField
+from oauth2_provider.models import AbstractApplication
 from oauth2_provider.settings import oauth2_settings
 from pytz import utc
 
@@ -43,3 +46,88 @@ class RestrictedApplication(models.Model):
         is set at the beginning of the epoch which is Jan. 1, 1970
         """
         return access_token.expires == datetime(1970, 1, 1, tzinfo=utc)
+
+
+class ScopedApplication(AbstractApplication):
+    """
+    Custom Django OAuth Toolkit Application model that enables the definition
+    of scopes that are authorized for the given Application.
+    """
+    FILTER_USER_ME = 'user:me'
+
+    # TODO: Remove the id field once we perform the inital migrations for this model.
+    # We need to copy data over from the oauth2_provider.models.Application model to
+    # this new model with the intial migration and the model IDs will need to match
+    # so that existing AccessTokens will still work when switching over to the new model.
+    # Once we have the data copied over we can move back to an auto-increment primary key.
+    id = models.IntegerField(primary_key=True)
+    scopes = ListCharField(
+        base_field=models.CharField(max_length=32),
+        size=25,
+        max_length=(25 * 33),  # 25 * 32 character scopes, plus commas
+        help_text=_('Comma-separated list of scopes that this application will be allowed to request.'),
+    )
+
+    class Meta:
+        app_label = 'oauth_dispatch'
+
+    def __unicode__(self):
+        """
+        Return a unicode representation of this object.
+        """
+        return u"<ScopedApplication '{name}'>".format(
+            name=self.name
+        )
+
+    @property
+    def authorization_filters(self):
+        """
+        Return the list of authorization filters for this application.
+        """
+        filters = [':'.join([org.provider_type, org.short_name]) for org in self.organizations.all()]
+        if self.authorization_grant_type == self.GRANT_CLIENT_CREDENTIALS:
+            filters.append(self.FILTER_USER_ME)
+        return filters
+
+
+class ScopedApplicationOrganization(models.Model):
+    """
+    Associates an organization to a given ScopedApplication including the
+    provider type of the organization so that organization-based filters
+    can be added to access tokens provided to the given Application.
+
+    See openedx/core/djangoapps/oauth_dispatch/docs/decisions/0007-include-organizations-in-tokens.rst
+    for the intended use of this model.
+    """
+    CONTENT_PROVIDER_TYPE = 'content_org'
+    ORGANIZATION_PROVIDER_TYPES = (
+        (CONTENT_PROVIDER_TYPE, _('Content Provider')),
+    )
+
+    # In practice, short_name should match the short_name of an Organization model.
+    # This is not a foreign key because the organizations app is not installed by default.
+    short_name = models.CharField(
+        max_length=255,
+        help_text=_('The short_name of an existing Organization.'),
+    )
+    provider_type = models.CharField(
+        max_length=32,
+        choices=ORGANIZATION_PROVIDER_TYPES,
+        default=CONTENT_PROVIDER_TYPE,
+    )
+    application = models.ForeignKey(
+        oauth2_settings.APPLICATION_MODEL,
+        related_name='organizations',
+    )
+
+    class Meta:
+        app_label = 'oauth_dispatch'
+
+    def __unicode__(self):
+        """
+        Return a unicode representation of this object.
+        """
+        return u"<ScopedApplicationOrganization '{application_name}':'{org}'>".format(
+            application_name=self.application.name,
+            org=self.short_name,
+        )
diff --git a/requirements/edx-sandbox/base.txt b/requirements/edx-sandbox/base.txt
index e9615245188a9774389fc35238b1b5dba49fb6cd..d5054928210f1e19f84ce9bd3fd6b0f2b91e3b2c 100644
--- a/requirements/edx-sandbox/base.txt
+++ b/requirements/edx-sandbox/base.txt
@@ -4,7 +4,6 @@
 #
 #    make upgrade
 #
-
 common/lib/calc
 common/lib/chem
 common/lib/sandbox-packages
diff --git a/requirements/edx-sandbox/shared.txt b/requirements/edx-sandbox/shared.txt
index 9967096c8c0ca1b638ed4eda31fe9bcb132006cc..9c112a860a4fec3a6e4194125cdbb4f92af9afeb 100644
--- a/requirements/edx-sandbox/shared.txt
+++ b/requirements/edx-sandbox/shared.txt
@@ -4,7 +4,6 @@
 #
 #    make upgrade
 #
-
 -e common/lib/calc
 -e common/lib/chem
 -e common/lib/sandbox-packages
diff --git a/requirements/edx/base.in b/requirements/edx/base.in
index 9a73deb015248f5b90068c481d7489edda8b8aa3..92d70aa0ff25764a5b53ad41233aa6571979eab3 100644
--- a/requirements/edx/base.in
+++ b/requirements/edx/base.in
@@ -46,6 +46,7 @@ django-memcached-hashring
 django-method-override==0.1.0
 django-model-utils==3.0.0
 django-mptt>=0.8.6,<0.9
+django-mysql
 django-oauth-toolkit==0.12.0
 django-pyfs
 django-ratelimit
diff --git a/requirements/edx/base.txt b/requirements/edx/base.txt
index bc68eb0d0f6a94b82c6fa89ed8fc7080fd6abeb5..2efae32450570df98798e3e72ab0e497f129d68e 100644
--- a/requirements/edx/base.txt
+++ b/requirements/edx/base.txt
@@ -4,7 +4,6 @@
 #
 #    make upgrade
 #
-
 -e git+https://github.com/edx/acid-block.git@e46f9cda8a03e121a00c7e347084d142d22ebfb7#egg=acid-xblock
 -e common/lib/calc
 -e common/lib/capa
@@ -84,6 +83,7 @@ django-method-override==0.1.0
 django-model-utils==3.0.0
 django-mptt==0.8.7
 django-multi-email-field==0.5.1  # via edx-enterprise
+django-mysql==2.3.0
 django-oauth-toolkit==0.12.0
 django-object-actions==0.10.0  # via edx-enterprise
 django-pyfs==2.0
@@ -93,7 +93,7 @@ django-require==1.0.11
 django-rest-swagger==2.2.0
 django-sekizai==0.10.0
 django-ses==0.8.4
-django-simple-history==2.1.0
+django-simple-history==2.1.1
 django-splash==0.2.2
 django-statici18n==1.4.0
 django-storages==1.4.1
diff --git a/requirements/edx/coverage.txt b/requirements/edx/coverage.txt
index c721171b4352594d172a109434b7ed4e726160b0..2ee117248633a7370d6ef9a90a4f4d4446b8a8b8 100644
--- a/requirements/edx/coverage.txt
+++ b/requirements/edx/coverage.txt
@@ -4,7 +4,6 @@
 #
 #    make upgrade
 #
-
 coverage==4.2
 diff-cover==0.9.8
 inflect==0.3.1            # via jinja2-pluralize
diff --git a/requirements/edx/development.txt b/requirements/edx/development.txt
index 358fbcd3f67c48f85d291c6a4c542a5a426b978a..069fbd6a30667ac77047d40153300d387ff097b9 100644
--- a/requirements/edx/development.txt
+++ b/requirements/edx/development.txt
@@ -4,7 +4,6 @@
 #
 #    make upgrade
 #
-
 -e git+https://github.com/edx/acid-block.git@e46f9cda8a03e121a00c7e347084d142d22ebfb7#egg=acid-xblock
 -e common/lib/calc
 -e common/lib/capa
@@ -44,7 +43,7 @@ git+https://github.com/edx-solutions/xblock-drag-and-drop-v2@v2.1.6#egg=xblock-d
 git+https://github.com/open-craft/xblock-poll@add89e14558c30f3c8dc7431e5cd6536fff6d941#egg=xblock-poll==1.5.1
 git+https://github.com/edx/xblock-utils.git@v1.1.1#egg=xblock-utils==1.1.1
 -e common/lib/xmodule
-alabaster==0.7.10         # via sphinx
+alabaster==0.7.11         # via sphinx
 amqp==1.4.9
 analytics-python==1.1.0
 anyjson==0.3.3
@@ -104,6 +103,7 @@ django-method-override==0.1.0
 django-model-utils==3.0.0
 django-mptt==0.8.7
 django-multi-email-field==0.5.1
+django-mysql==2.3.0
 django-oauth-toolkit==0.12.0
 django-object-actions==0.10.0
 django-pyfs==2.0
@@ -113,7 +113,7 @@ django-require==1.0.11
 django-rest-swagger==2.2.0
 django-sekizai==0.10.0
 django-ses==0.8.4
-django-simple-history==2.1.0
+django-simple-history==2.1.1
 django-splash==0.2.2
 django-statici18n==1.4.0
 django-storages==1.4.1
@@ -156,7 +156,7 @@ event-tracking==0.2.4
 execnet==1.5.0
 extras==1.0.0
 factory_boy==2.8.1
-faker==0.8.15
+faker==0.8.16
 feedparser==5.1.3
 firebase-token-generator==1.3.2
 first==2.0.1
@@ -270,7 +270,7 @@ pytest-django==3.1.2
 pytest-forked==0.2
 pytest-randomly==1.2.3
 pytest-xdist==1.22.2
-pytest==3.6.1
+pytest==3.6.2
 python-dateutil==2.4.0
 python-levenshtein==0.12.0
 python-memcached==1.48
@@ -316,7 +316,7 @@ sqlparse==0.2.4           # via django-debug-toolbar
 stevedore==1.10.0
 sure==1.4.11
 sympy==0.7.1
-testfixtures==6.1.0
+testfixtures==6.2.0
 testtools==2.3.0
 text-unidecode==1.2
 tox-battery==0.5.1
diff --git a/requirements/edx/paver.txt b/requirements/edx/paver.txt
index 697c166940116662a6a5e67dc7a7300492608635..9a6a6a4b3ee23d2de190162cd698048648282040 100644
--- a/requirements/edx/paver.txt
+++ b/requirements/edx/paver.txt
@@ -4,7 +4,6 @@
 #
 #    make upgrade
 #
-
 argh==0.26.2              # via watchdog
 argparse==1.4.0           # via stevedore
 edx-opaque-keys==0.4.4
diff --git a/requirements/edx/pip-tools.txt b/requirements/edx/pip-tools.txt
index 44aa65b2a3db3f7d157707ec5a6a178b34be3a38..e7027f3fb21c5071c9b7628a407345d2b12bd001 100644
--- a/requirements/edx/pip-tools.txt
+++ b/requirements/edx/pip-tools.txt
@@ -4,7 +4,6 @@
 #
 #    make upgrade
 #
-
 click==6.7                # via pip-tools
 first==2.0.1              # via pip-tools
 pip-tools==2.0.2
diff --git a/requirements/edx/testing.txt b/requirements/edx/testing.txt
index 40bdf4608b3173c4b039d62870174b6d8589845e..f7c09f2049ede6d4a1d529939387109cba47fde2 100644
--- a/requirements/edx/testing.txt
+++ b/requirements/edx/testing.txt
@@ -4,7 +4,6 @@
 #
 #    make upgrade
 #
-
 -e git+https://github.com/edx/acid-block.git@e46f9cda8a03e121a00c7e347084d142d22ebfb7#egg=acid-xblock
 -e common/lib/calc
 -e common/lib/capa
@@ -100,6 +99,7 @@ django-method-override==0.1.0
 django-model-utils==3.0.0
 django-mptt==0.8.7
 django-multi-email-field==0.5.1
+django-mysql==2.3.0
 django-oauth-toolkit==0.12.0
 django-object-actions==0.10.0
 django-pyfs==2.0
@@ -109,7 +109,7 @@ django-require==1.0.11
 django-rest-swagger==2.2.0
 django-sekizai==0.10.0
 django-ses==0.8.4
-django-simple-history==2.1.0
+django-simple-history==2.1.1
 django-splash==0.2.2
 django-statici18n==1.4.0
 django-storages==1.4.1
@@ -150,7 +150,7 @@ event-tracking==0.2.4
 execnet==1.5.0            # via pytest-xdist
 extras==1.0.0             # via python-subunit, testtools
 factory_boy==2.8.1
-faker==0.8.15             # via factory-boy
+faker==0.8.16             # via factory-boy
 feedparser==5.1.3
 firebase-token-generator==1.3.2
 fixtures==3.0.0           # via testtools
@@ -259,7 +259,7 @@ pytest-django==3.1.2
 pytest-forked==0.2        # via pytest-xdist
 pytest-randomly==1.2.3
 pytest-xdist==1.22.2
-pytest==3.6.1
+pytest==3.6.2
 python-dateutil==2.4.0
 python-levenshtein==0.12.0
 python-memcached==1.48
@@ -300,7 +300,7 @@ splinter==0.8.0
 stevedore==1.10.0
 sure==1.4.11
 sympy==0.7.1
-testfixtures==6.1.0
+testfixtures==6.2.0
 testtools==2.3.0          # via fixtures, python-subunit
 text-unidecode==1.2       # via faker
 tox-battery==0.5.1