diff --git a/TODO b/TODO
index 974f0afc90448ed97ab991fd9af42a947aab64fd..e4ef7e452ae4a01f7f0ed8eb4c10fdd632918dc8 100644
--- a/TODO
+++ b/TODO
@@ -10,8 +10,6 @@
 
 - MOSS submission
 
-- Don't store current flow session in cookie, ever.
-
 - Redo permissions system
 
 - Custom matcher classes
diff --git a/course/flow.py b/course/flow.py
index d0dc369caf7216ca9dcbce1e7670649cd39e30aa..42d2828b33c5097487d4f9489e684d6036148879 100644
--- a/course/flow.py
+++ b/course/flow.py
@@ -61,15 +61,6 @@ from course.utils import (
 from course.views import get_now_or_fake_time
 
 
-def get_flow_session_id_map(request):
-    result = request.session.setdefault("flow_session_id_map", {})
-
-    # Tell Django: This session has been modified, persist it.
-    request.session["flow_session_id_map"] = result
-
-    return result
-
-
 # {{{ grade page visit
 
 def grade_page_visit(visit, visit_grade_model=FlowPageVisitGrade,
@@ -739,11 +730,9 @@ def start_flow(pctx, flow_identifier):
                     or resume_session.in_progress):
                 raise PermissionDenied("not allowed to resume session")
 
-            get_flow_session_id_map(request)[flow_identifier] = resume_session_id
-
             return redirect("course.flow.view_flow_page",
                     pctx.course.identifier,
-                    flow_identifier,
+                    resume_session_id,
                     0)
 
         elif ("start_no_credit" in request.POST
@@ -789,17 +778,13 @@ def start_flow(pctx, flow_identifier):
                 get_flow_grading_opportunity(
                         pctx.course, flow_identifier, fctx.flow_desc)
 
-            get_flow_session_id_map(request)[flow_identifier] = session.id
-
             page_count = set_up_flow_session_page_data(fctx.repo, session,
                     pctx.course.identifier, fctx.flow_desc, pctx.course_commit_sha)
             session.page_count = page_count
             session.save()
 
             return redirect("course.flow.view_flow_page",
-                    pctx.course.identifier,
-                    flow_identifier,
-                    0)
+                    pctx.course.identifier, session.id, 0)
 
         else:
             raise SuspiciousOperation("unrecognized POST action")
@@ -860,21 +845,24 @@ def start_flow(pctx, flow_identifier):
 
 # {{{ view: flow page
 
-def find_current_flow_session(request, course, flow_identifier):
-    flow_session = None
-    flow_session_id = get_flow_session_id_map(request).get(flow_identifier)
-
-    if flow_session_id is not None:
-        try:
-            flow_session = FlowSession.objects.get(id=flow_session_id)
-        except ObjectDoesNotExist:
-            return None
+def get_and_check_flow_session(pctx, flow_session_id):
+    try:
+        flow_session = FlowSession.objects.get(id=flow_session_id)
+    except ObjectDoesNotExist:
+        raise http.Http404()
 
-        if flow_session.course.pk != course.pk:
-            return None
+    if pctx.role in [
+            participation_role.instructor,
+            participation_role.teaching_assistant]:
+        pass
+    elif pctx.role == participation_role.student:
+        if pctx.participation != flow_session.participation:
+            raise PermissionDenied("may not view other people's sessions")
+    else:
+        raise PermissionDenied()
 
-        if flow_session.flow_id != flow_identifier:
-            return None
+    if flow_session.course.pk != pctx.course.pk:
+        raise SuspiciousOperation()
 
     return flow_session
 
@@ -935,11 +923,13 @@ def create_flow_page_visit(request, flow_session, page_data):
 
 
 @course_view
-def view_flow_page(pctx, flow_identifier, ordinal):
+def view_flow_page(pctx, flow_session_id, ordinal):
     request = pctx.request
 
-    flow_session = find_current_flow_session(
-            request, pctx.course, flow_identifier)
+    flow_session_id = int(flow_session_id)
+    flow_session = get_and_check_flow_session(
+            pctx, flow_session_id)
+    flow_identifier = flow_session.flow_id
 
     if flow_session is None:
         messages.add_message(request, messages.WARNING,
@@ -996,7 +986,7 @@ def view_flow_page(pctx, flow_identifier, ordinal):
     if request.method == "POST":
         if "finish" in request.POST:
             return redirect("course.flow.finish_flow_session_view",
-                    pctx.course.identifier, flow_identifier)
+                    pctx.course.identifier, flow_session_id)
         else:
             # reject answer update if flow is not in-progress
             if not flow_session.in_progress:
@@ -1071,12 +1061,12 @@ def view_flow_page(pctx, flow_identifier, ordinal):
                         and not will_receive_feedback(permissions)):
                     return redirect("course.flow.view_flow_page",
                             pctx.course.identifier,
-                            flow_identifier,
+                            flow_session_id,
                             fpctx.ordinal + 1)
                 elif (pressed_button == "save_and_finish"
                         and not will_receive_feedback(permissions)):
                     return redirect("course.flow.finish_flow_session_view",
-                            pctx.course.identifier, flow_identifier)
+                            pctx.course.identifier, flow_session_id)
                 else:
                     form = fpctx.page.make_form(
                             page_context, page_data.data,
@@ -1286,22 +1276,15 @@ def update_expiration_mode(pctx, flow_session_id):
 
 @transaction.atomic
 @course_view
-def finish_flow_session_view(pctx, flow_identifier):
+def finish_flow_session_view(pctx, flow_session_id):
     now_datetime = get_now_or_fake_time(pctx.request)
 
     request = pctx.request
 
-    flow_session = find_current_flow_session(
-            request, pctx.course, flow_identifier)
-
-    if flow_session is None:
-        messages.add_message(request, messages.WARNING,
-                "No session record found for this flow. "
-                "Redirected to flow start page.")
-
-        return redirect("course.flow.start_flow",
-                pctx.course.identifier,
-                flow_identifier)
+    flow_session_id = int(flow_session_id)
+    flow_session = get_and_check_flow_session(
+            pctx, flow_session_id)
+    flow_identifier = flow_session.flow_id
 
     fctx = FlowContext(pctx.repo, pctx.course, flow_identifier,
             participation=pctx.participation,
@@ -1343,9 +1326,6 @@ def finish_flow_session_view(pctx, flow_identifier):
         if not flow_session.in_progress:
             raise PermissionDenied("Can't end a session that's already ended")
 
-        # Actually end the flow session
-        get_flow_session_id_map(request)[flow_identifier] = None
-
         grade_info = finish_flow_session(
                 fctx, flow_session, current_access_rule,
                 now_datetime=now_datetime)
@@ -1360,6 +1340,7 @@ def finish_flow_session_view(pctx, flow_identifier):
             return render_finish_response(
                     "course/flow-completion.html",
                     last_page_nr=None,
+                    flow_session=flow_session,
                     completion_text=completion_text)
 
     if not is_graded_flow:
@@ -1368,6 +1349,7 @@ def finish_flow_session_view(pctx, flow_identifier):
         return render_finish_response(
                 "course/flow-completion.html",
                 last_page_nr=flow_session.page_count-1,
+                flow_session=flow_session,
                 completion_text=completion_text)
 
     elif not flow_session.in_progress:
@@ -1384,6 +1366,7 @@ def finish_flow_session_view(pctx, flow_identifier):
         return render_finish_response(
                 "course/flow-confirm-completion.html",
                 last_page_nr=flow_session.page_count-1,
+                flow_session=flow_session,
                 answered_count=answered_count,
                 unanswered_count=unanswered_count,
                 total_count=answered_count+unanswered_count)
diff --git a/course/models.py b/course/models.py
index a906b16fabeeafa14a22335dc260198350747b6b..7b2ddf5d7a6be517988279e0bf66095b5c577707 100644
--- a/course/models.py
+++ b/course/models.py
@@ -98,7 +98,8 @@ class Course(models.Model):
             "<tt>git://github.com/inducer/courseflow-sample</tt> "
             "to get some sample content.")
     ssh_private_key = models.TextField(blank=True,
-            help_text="An SSH private key to use for Git authentication")
+            help_text="An SSH private key to use for Git authentication. "
+            "Not needed for the sample URL above.")
 
     course_file = models.CharField(max_length=200,
             default="course.yml",
@@ -154,6 +155,8 @@ class Course(models.Model):
 # }}}
 
 
+# {{{ event
+
 class Event(models.Model):
     """An event is an identifier that can be used to specify dates in
     course content.
@@ -183,6 +186,8 @@ class Event(models.Model):
         else:
             return self.kind
 
+# }}}
+
 
 # {{{ participation
 
@@ -482,8 +487,6 @@ def get_feedback_for_grade(grade):
 
 # }}}
 
-# }}}
-
 
 # {{{ flow access
 
diff --git a/course/templates/course/flow-completion-grade.html b/course/templates/course/flow-completion-grade.html
index 8c86e14652e07af7e83ba13a911ba00c9ddc27c6..ac7fe5128853e19b26e57cc74dec36bed71a3454 100644
--- a/course/templates/course/flow-completion-grade.html
+++ b/course/templates/course/flow-completion-grade.html
@@ -63,10 +63,7 @@
   <div class="well flow-well">
     <a class="btn btn-default"
       href="{% url "course.flow.start_flow" course.identifier flow_identifier %}"
-      role="button">&laquo; Start over / Review</a>
-    <a class="btn btn-default"
-      href="{% url "course.views.course_page" course.identifier %}"
-      role="button">To course page &raquo;</a>
+      role="button">&laquo; Back to start page</a>
   </div>
 
 {% endblock %}
diff --git a/course/templates/course/flow-completion.html b/course/templates/course/flow-completion.html
index 1e57290524f0bd79e05dab00deeff4376fc713bd..a9c663ef77709b22d1aebd2136c862acc22bf235 100644
--- a/course/templates/course/flow-completion.html
+++ b/course/templates/course/flow-completion.html
@@ -8,17 +8,9 @@
   {{ completion_text|safe }}
 
   <div class="well flow-well">
-    {% if last_page_nr %}
-      <a class="btn btn-default"
-        href="{% url "course.flow.view_flow_page" course.identifier flow_identifier last_page_nr %}"
-        role="button">&laquo; Go back</a>
-    {% endif %}
     <a class="btn btn-default"
       href="{% url "course.flow.start_flow" course.identifier flow_identifier %}"
-      role="button">&laquo; Start over</a>
-    <a class="btn btn-default"
-      href="{% url "course.views.course_page" course.identifier %}"
-      role="button">To course page &raquo;</a>
+      role="button">&laquo; Back to start page</a>
   </div>
 
 {% endblock %}
diff --git a/course/templates/course/flow-confirm-completion.html b/course/templates/course/flow-confirm-completion.html
index 82ebbb8917ce876d3fe9c67904c93e90af04ad7e..3fa3d7a2316c9423f0dcfec1efffa63e006b3119 100644
--- a/course/templates/course/flow-confirm-completion.html
+++ b/course/templates/course/flow-confirm-completion.html
@@ -36,7 +36,7 @@
       {% csrf_token %}
 
       <a class="btn btn-default"
-        href="{% url "course.flow.view_flow_page" course.identifier flow_identifier last_page_nr %}"
+        href="{% url "course.flow.view_flow_page" course.identifier flow_session.id last_page_nr %}"
         role="button">&laquo; Go back</a>
 
       <button type="submit" name="submit" class="btn btn-primary">Confirm: Submit answers and end session</button>
diff --git a/course/templates/course/flow-page.html b/course/templates/course/flow-page.html
index bf2e094d7b5b5891842b1d0f05d35ec0ef069e2c..b01469a97cc91f3db1298d635182c52a7c53e606 100644
--- a/course/templates/course/flow-page.html
+++ b/course/templates/course/flow-page.html
@@ -10,7 +10,7 @@
 
 {% block content %}
   <form
-    action="{% url "course.flow.view_flow_page" course.identifier flow_identifier page_data.ordinal %}"
+    action="{% url "course.flow.view_flow_page" course.identifier flow_session.id page_data.ordinal %}"
     class="navigation-form"
     method="POST">
 
@@ -20,7 +20,7 @@
       <div class="flow-nav">
         {% if page_data.ordinal > 0 %}
           <a class="btn btn-default cf-nav-button"
-            href="{% url "course.flow.view_flow_page" course.identifier flow_identifier page_data.previous_ordinal %}"
+            href="{% url "course.flow.view_flow_page" course.identifier flow_session.id page_data.previous_ordinal %}"
             role="button">&laquo; Previous</a>
         {% else %}
           <a class="btn btn-default cf-nav-button disabled"
@@ -29,7 +29,7 @@
         {% endif %}
         {% if page_data.next_ordinal < flow_session.page_count %}
           <a class="btn btn-default cf-nav-button"
-            href="{% url "course.flow.view_flow_page" course.identifier flow_identifier page_data.next_ordinal %}"
+            href="{% url "course.flow.view_flow_page" course.identifier flow_session.id page_data.next_ordinal %}"
             role="button">Next &raquo;</a>
         {% else %}
           <a class="btn btn-default cf-nav-button disabled"
@@ -63,7 +63,7 @@
           {% if page_nr == page_data.ordinal %}
             <span class="cf-flow-page-number cf-current btn btn-default btn-xs disabled">{{ shown_page_nr }}</span>
           {% else %}
-            <a href="{% url "course.flow.view_flow_page" course.identifier flow_identifier page_nr %}">
+            <a href="{% url "course.flow.view_flow_page" course.identifier flow_session.id page_nr %}">
             <span class="cf-flow-page-number btn btn-default btn-xs
               {% if page_nr < page_data.ordinal %}
                 cf-prior
diff --git a/courseflow/urls.py b/courseflow/urls.py
index 110a0c66fbf57ad8c03f501998d79758b22a7028..253b66ed777ac365fa68aadda2bb27a63a4f7d42 100644
--- a/courseflow/urls.py
+++ b/courseflow/urls.py
@@ -216,8 +216,8 @@ urlpatterns = patterns('',
          "course.flow.start_flow",),
     url(r"^course"
         "/(?P<course_identifier>[-a-zA-Z0-9]+)"
-        "/flow"
-        "/(?P<flow_identifier>[-_a-zA-Z0-9]+)"
+        "/flow-session/"
+        "/(?P<flow_session_id>[0-9]+)"
         "/(?P<ordinal>[0-9]+)"
         "/$",
         "course.flow.view_flow_page",),
@@ -230,8 +230,8 @@ urlpatterns = patterns('',
         "course.flow.update_expiration_mode",),
     url(r"^course"
         "/(?P<course_identifier>[-a-zA-Z0-9]+)"
-        "/flow"
-        "/(?P<flow_identifier>[-_a-zA-Z0-9]+)"
+        "/flow-session"
+        "/(?P<flow_session_id>[0-9]+)"
         "/finish"
         "/$",
         "course.flow.finish_flow_session_view",),