We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Ensure relevant analytics events are fired for Login.gov IAL2 flow
Design to collaborate with Dev to ensure the behaviors they are interested in understanding are defined in Amplitude. 

- [x] `cancel_sign_in`

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `benefits/oauth/analytics.py`
Content:
```
1 """
2 The oauth application: analytics implementation.
3 """
4 from benefits.core import analytics as core, session
5 
6 
7 class OAuthEvent(core.Event):
8     """Base OAuth analytics event."""
9 
10     def __init__(self, request, event_type):
11         super().__init__(request, event_type)
12         verifier = session.verifier(request)
13         self.update_event_properties(auth_provider=verifier.auth_provider.client_name)
14 
15 
16 class StartedSignInEvent(OAuthEvent):
17     """Analytics event representing the beginning of the OAuth sign in flow."""
18 
19     def __init__(self, request):
20         super().__init__(request, "started sign in")
21 
22 
23 class FinishedSignInEvent(OAuthEvent):
24     """Analytics event representing the end of the OAuth sign in flow."""
25 
26     def __init__(self, request):
27         super().__init__(request, "finished sign in")
28 
29 
30 class StartedSignOutEvent(OAuthEvent):
31     """Analytics event representing the beginning of application sign out."""
32 
33     def __init__(self, request):
34         super().__init__(request, "started signed out")
35 
36 
37 class FinishedSignOutEvent(OAuthEvent):
38     """Analytics event representing the end of application sign out."""
39 
40     def __init__(self, request):
41         super().__init__(request, "finished sign out")
42         self.update_event_properties(origin=session.origin(request))
43 
44 
45 def started_sign_in(request):
46     """Send the "started sign in" analytics event."""
47     core.send_event(StartedSignInEvent(request))
48 
49 
50 def finished_sign_in(request):
51     """Send the "finished sign in" analytics event."""
52     core.send_event(FinishedSignInEvent(request))
53 
54 
55 def started_sign_out(request):
56     """Send the "started signed out" analytics event."""
57     core.send_event(StartedSignOutEvent(request))
58 
59 
60 def finished_sign_out(request):
61     """Send the "finished sign out" analytics event."""
62     core.send_event(FinishedSignOutEvent(request))
63
```

Path: `benefits/oauth/views.py`
Content:
```
1 import logging
2 
3 from django.shortcuts import redirect
4 from django.urls import reverse
5 from django.utils.decorators import decorator_from_middleware
6 
7 from benefits.core import session
8 from benefits.core.middleware import VerifierSessionRequired
9 from . import analytics, redirects
10 from .client import oauth
11 
12 
13 logger = logging.getLogger(__name__)
14 
15 
16 ROUTE_AUTH = "oauth:authorize"
17 ROUTE_START = "eligibility:start"
18 ROUTE_CONFIRM = "eligibility:confirm"
19 ROUTE_UNVERIFIED = "eligibility:unverified"
20 ROUTE_POST_LOGOUT = "oauth:post_logout"
21 
22 
23 @decorator_from_middleware(VerifierSessionRequired)
24 def login(request):
25     """View implementing OIDC authorize_redirect."""
26     verifier = session.verifier(request)
27     oauth_client = oauth.create_client(verifier.auth_provider.client_name)
28 
29     if not oauth_client:
30         raise Exception(f"oauth_client not registered: {verifier.auth_provider.client_name}")
31 
32     route = reverse(ROUTE_AUTH)
33     redirect_uri = redirects.generate_redirect_uri(request, route)
34 
35     logger.debug(f"OAuth authorize_redirect with redirect_uri: {redirect_uri}")
36 
37     analytics.started_sign_in(request)
38 
39     return oauth_client.authorize_redirect(request, redirect_uri)
40 
41 
42 @decorator_from_middleware(VerifierSessionRequired)
43 def authorize(request):
44     """View implementing OIDC token authorization."""
45     verifier = session.verifier(request)
46     oauth_client = oauth.create_client(verifier.auth_provider.client_name)
47 
48     if not oauth_client:
49         raise Exception(f"oauth_client not registered: {verifier.auth_provider.client_name}")
50 
51     logger.debug("Attempting to authorize OAuth access token")
52     token = oauth_client.authorize_access_token(request)
53 
54     if token is None:
55         logger.warning("Could not authorize OAuth access token")
56         return redirect(ROUTE_START)
57 
58     logger.debug("OAuth access token authorized")
59 
60     # We store the id_token in the user's session. This is the minimal amount of information needed later to log the user out.
61     id_token = token["id_token"]
62 
63     # We store the returned claim in case it can be used later in eligibility verification.
64     verifier_claim = verifier.auth_provider.claim
65     stored_claim = None
66 
67     if verifier_claim:
68         userinfo = token.get("userinfo")
69         # the claim comes back in userinfo like { "claim": "True" | "False" }
70         claim_flag = (userinfo.get(verifier_claim) if userinfo else "false").lower() == "true"
71         # if userinfo contains our claim and the flag is true, store the *claim*
72         stored_claim = verifier_claim if claim_flag else None
73 
74     session.update(request, oauth_token=id_token, oauth_claim=stored_claim)
75 
76     analytics.finished_sign_in(request)
77 
78     return redirect(ROUTE_CONFIRM)
79 
80 
81 def cancel(request):
82     """View implementing cancellation of OIDC authorization."""
83     return redirect(ROUTE_UNVERIFIED)
84 
85 
86 @decorator_from_middleware(VerifierSessionRequired)
87 def logout(request):
88     """View implementing OIDC and application sign out."""
89     verifier = session.verifier(request)
90     oauth_client = oauth.create_client(verifier.auth_provider.client_name)
91 
92     if not oauth_client:
93         raise Exception(f"oauth_client not registered: {verifier.auth_provider.client_name}")
94 
95     analytics.started_sign_out(request)
96 
97     # overwrite the oauth session token, the user is signed out of the app
98     token = session.oauth_token(request)
99     session.logout(request)
100 
101     route = reverse(ROUTE_POST_LOGOUT)
102     redirect_uri = redirects.generate_redirect_uri(request, route)
103 
104     logger.debug(f"OAuth end_session_endpoint with redirect_uri: {redirect_uri}")
105 
106     # send the user through the end_session_endpoint, redirecting back to
107     # the post_logout route
108     return redirects.deauthorize_redirect(oauth_client, token, redirect_uri)
109 
110 
111 def post_logout(request):
112     """View routes the user to their origin after sign out."""
113 
114     analytics.finished_sign_out(request)
115 
116     origin = session.origin(request)
117     return redirect(origin)
118
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/benefits/oauth/analytics.py b/benefits/oauth/analytics.py
--- a/benefits/oauth/analytics.py
+++ b/benefits/oauth/analytics.py
@@ -20,6 +20,13 @@
         super().__init__(request, "started sign in")
 
 
+class CanceledSignInEvent(OAuthEvent):
+    """Analytics event representing the canceling of application sign in."""
+
+    def __init__(self, request):
+        super().__init__(request, "canceled sign in")
+
+
 class FinishedSignInEvent(OAuthEvent):
     """Analytics event representing the end of the OAuth sign in flow."""
 
@@ -31,7 +38,7 @@
     """Analytics event representing the beginning of application sign out."""
 
     def __init__(self, request):
-        super().__init__(request, "started signed out")
+        super().__init__(request, "started sign out")
 
 
 class FinishedSignOutEvent(OAuthEvent):
@@ -47,6 +54,11 @@
     core.send_event(StartedSignInEvent(request))
 
 
+def canceled_sign_in(request):
+    """Send the "canceled sign in" analytics event."""
+    core.send_event(CanceledSignInEvent(request))
+
+
 def finished_sign_in(request):
     """Send the "finished sign in" analytics event."""
     core.send_event(FinishedSignInEvent(request))
diff --git a/benefits/oauth/views.py b/benefits/oauth/views.py
--- a/benefits/oauth/views.py
+++ b/benefits/oauth/views.py
@@ -80,6 +80,9 @@
 
 def cancel(request):
     """View implementing cancellation of OIDC authorization."""
+
+    analytics.canceled_sign_in(request)
+
     return redirect(ROUTE_UNVERIFIED)

{"golden_diff": "diff --git a/benefits/oauth/analytics.py b/benefits/oauth/analytics.py\n--- a/benefits/oauth/analytics.py\n+++ b/benefits/oauth/analytics.py\n@@ -20,6 +20,13 @@\n         super().__init__(request, \"started sign in\")\n \n \n+class CanceledSignInEvent(OAuthEvent):\n+    \"\"\"Analytics event representing the canceling of application sign in.\"\"\"\n+\n+    def __init__(self, request):\n+        super().__init__(request, \"canceled sign in\")\n+\n+\n class FinishedSignInEvent(OAuthEvent):\n     \"\"\"Analytics event representing the end of the OAuth sign in flow.\"\"\"\n \n@@ -31,7 +38,7 @@\n     \"\"\"Analytics event representing the beginning of application sign out.\"\"\"\n \n     def __init__(self, request):\n-        super().__init__(request, \"started signed out\")\n+        super().__init__(request, \"started sign out\")\n \n \n class FinishedSignOutEvent(OAuthEvent):\n@@ -47,6 +54,11 @@\n     core.send_event(StartedSignInEvent(request))\n \n \n+def canceled_sign_in(request):\n+    \"\"\"Send the \"canceled sign in\" analytics event.\"\"\"\n+    core.send_event(CanceledSignInEvent(request))\n+\n+\n def finished_sign_in(request):\n     \"\"\"Send the \"finished sign in\" analytics event.\"\"\"\n     core.send_event(FinishedSignInEvent(request))\ndiff --git a/benefits/oauth/views.py b/benefits/oauth/views.py\n--- a/benefits/oauth/views.py\n+++ b/benefits/oauth/views.py\n@@ -80,6 +80,9 @@\n \n def cancel(request):\n     \"\"\"View implementing cancellation of OIDC authorization.\"\"\"\n+\n+    analytics.canceled_sign_in(request)\n+\n     return redirect(ROUTE_UNVERIFIED)\n", "issue": "Ensure relevant analytics events are fired for Login.gov IAL2 flow\nDesign to collaborate with Dev to ensure the behaviors they are interested in understanding are defined in Amplitude. \r\n\r\n- [x] `cancel_sign_in`\n", "before_files": [{"content": "\"\"\"\nThe oauth application: analytics implementation.\n\"\"\"\nfrom benefits.core import analytics as core, session\n\n\nclass OAuthEvent(core.Event):\n    \"\"\"Base OAuth analytics event.\"\"\"\n\n    def __init__(self, request, event_type):\n        super().__init__(request, event_type)\n        verifier = session.verifier(request)\n        self.update_event_properties(auth_provider=verifier.auth_provider.client_name)\n\n\nclass StartedSignInEvent(OAuthEvent):\n    \"\"\"Analytics event representing the beginning of the OAuth sign in flow.\"\"\"\n\n    def __init__(self, request):\n        super().__init__(request, \"started sign in\")\n\n\nclass FinishedSignInEvent(OAuthEvent):\n    \"\"\"Analytics event representing the end of the OAuth sign in flow.\"\"\"\n\n    def __init__(self, request):\n        super().__init__(request, \"finished sign in\")\n\n\nclass StartedSignOutEvent(OAuthEvent):\n    \"\"\"Analytics event representing the beginning of application sign out.\"\"\"\n\n    def __init__(self, request):\n        super().__init__(request, \"started signed out\")\n\n\nclass FinishedSignOutEvent(OAuthEvent):\n    \"\"\"Analytics event representing the end of application sign out.\"\"\"\n\n    def __init__(self, request):\n        super().__init__(request, \"finished sign out\")\n        self.update_event_properties(origin=session.origin(request))\n\n\ndef started_sign_in(request):\n    \"\"\"Send the \"started sign in\" analytics event.\"\"\"\n    core.send_event(StartedSignInEvent(request))\n\n\ndef finished_sign_in(request):\n    \"\"\"Send the \"finished sign in\" analytics event.\"\"\"\n    core.send_event(FinishedSignInEvent(request))\n\n\ndef started_sign_out(request):\n    \"\"\"Send the \"started signed out\" analytics event.\"\"\"\n    core.send_event(StartedSignOutEvent(request))\n\n\ndef finished_sign_out(request):\n    \"\"\"Send the \"finished sign out\" analytics event.\"\"\"\n    core.send_event(FinishedSignOutEvent(request))\n", "path": "benefits/oauth/analytics.py"}, {"content": "import logging\n\nfrom django.shortcuts import redirect\nfrom django.urls import reverse\nfrom django.utils.decorators import decorator_from_middleware\n\nfrom benefits.core import session\nfrom benefits.core.middleware import VerifierSessionRequired\nfrom . import analytics, redirects\nfrom .client import oauth\n\n\nlogger = logging.getLogger(__name__)\n\n\nROUTE_AUTH = \"oauth:authorize\"\nROUTE_START = \"eligibility:start\"\nROUTE_CONFIRM = \"eligibility:confirm\"\nROUTE_UNVERIFIED = \"eligibility:unverified\"\nROUTE_POST_LOGOUT = \"oauth:post_logout\"\n\n\n@decorator_from_middleware(VerifierSessionRequired)\ndef login(request):\n    \"\"\"View implementing OIDC authorize_redirect.\"\"\"\n    verifier = session.verifier(request)\n    oauth_client = oauth.create_client(verifier.auth_provider.client_name)\n\n    if not oauth_client:\n        raise Exception(f\"oauth_client not registered: {verifier.auth_provider.client_name}\")\n\n    route = reverse(ROUTE_AUTH)\n    redirect_uri = redirects.generate_redirect_uri(request, route)\n\n    logger.debug(f\"OAuth authorize_redirect with redirect_uri: {redirect_uri}\")\n\n    analytics.started_sign_in(request)\n\n    return oauth_client.authorize_redirect(request, redirect_uri)\n\n\n@decorator_from_middleware(VerifierSessionRequired)\ndef authorize(request):\n    \"\"\"View implementing OIDC token authorization.\"\"\"\n    verifier = session.verifier(request)\n    oauth_client = oauth.create_client(verifier.auth_provider.client_name)\n\n    if not oauth_client:\n        raise Exception(f\"oauth_client not registered: {verifier.auth_provider.client_name}\")\n\n    logger.debug(\"Attempting to authorize OAuth access token\")\n    token = oauth_client.authorize_access_token(request)\n\n    if token is None:\n        logger.warning(\"Could not authorize OAuth access token\")\n        return redirect(ROUTE_START)\n\n    logger.debug(\"OAuth access token authorized\")\n\n    # We store the id_token in the user's session. This is the minimal amount of information needed later to log the user out.\n    id_token = token[\"id_token\"]\n\n    # We store the returned claim in case it can be used later in eligibility verification.\n    verifier_claim = verifier.auth_provider.claim\n    stored_claim = None\n\n    if verifier_claim:\n        userinfo = token.get(\"userinfo\")\n        # the claim comes back in userinfo like { \"claim\": \"True\" | \"False\" }\n        claim_flag = (userinfo.get(verifier_claim) if userinfo else \"false\").lower() == \"true\"\n        # if userinfo contains our claim and the flag is true, store the *claim*\n        stored_claim = verifier_claim if claim_flag else None\n\n    session.update(request, oauth_token=id_token, oauth_claim=stored_claim)\n\n    analytics.finished_sign_in(request)\n\n    return redirect(ROUTE_CONFIRM)\n\n\ndef cancel(request):\n    \"\"\"View implementing cancellation of OIDC authorization.\"\"\"\n    return redirect(ROUTE_UNVERIFIED)\n\n\n@decorator_from_middleware(VerifierSessionRequired)\ndef logout(request):\n    \"\"\"View implementing OIDC and application sign out.\"\"\"\n    verifier = session.verifier(request)\n    oauth_client = oauth.create_client(verifier.auth_provider.client_name)\n\n    if not oauth_client:\n        raise Exception(f\"oauth_client not registered: {verifier.auth_provider.client_name}\")\n\n    analytics.started_sign_out(request)\n\n    # overwrite the oauth session token, the user is signed out of the app\n    token = session.oauth_token(request)\n    session.logout(request)\n\n    route = reverse(ROUTE_POST_LOGOUT)\n    redirect_uri = redirects.generate_redirect_uri(request, route)\n\n    logger.debug(f\"OAuth end_session_endpoint with redirect_uri: {redirect_uri}\")\n\n    # send the user through the end_session_endpoint, redirecting back to\n    # the post_logout route\n    return redirects.deauthorize_redirect(oauth_client, token, redirect_uri)\n\n\ndef post_logout(request):\n    \"\"\"View routes the user to their origin after sign out.\"\"\"\n\n    analytics.finished_sign_out(request)\n\n    origin = session.origin(request)\n    return redirect(origin)\n", "path": "benefits/oauth/views.py"}], "after_files": [{"content": "\"\"\"\nThe oauth application: analytics implementation.\n\"\"\"\nfrom benefits.core import analytics as core, session\n\n\nclass OAuthEvent(core.Event):\n    \"\"\"Base OAuth analytics event.\"\"\"\n\n    def __init__(self, request, event_type):\n        super().__init__(request, event_type)\n        verifier = session.verifier(request)\n        self.update_event_properties(auth_provider=verifier.auth_provider.client_name)\n\n\nclass StartedSignInEvent(OAuthEvent):\n    \"\"\"Analytics event representing the beginning of the OAuth sign in flow.\"\"\"\n\n    def __init__(self, request):\n        super().__init__(request, \"started sign in\")\n\n\nclass CanceledSignInEvent(OAuthEvent):\n    \"\"\"Analytics event representing the canceling of application sign in.\"\"\"\n\n    def __init__(self, request):\n        super().__init__(request, \"canceled sign in\")\n\n\nclass FinishedSignInEvent(OAuthEvent):\n    \"\"\"Analytics event representing the end of the OAuth sign in flow.\"\"\"\n\n    def __init__(self, request):\n        super().__init__(request, \"finished sign in\")\n\n\nclass StartedSignOutEvent(OAuthEvent):\n    \"\"\"Analytics event representing the beginning of application sign out.\"\"\"\n\n    def __init__(self, request):\n        super().__init__(request, \"started sign out\")\n\n\nclass FinishedSignOutEvent(OAuthEvent):\n    \"\"\"Analytics event representing the end of application sign out.\"\"\"\n\n    def __init__(self, request):\n        super().__init__(request, \"finished sign out\")\n        self.update_event_properties(origin=session.origin(request))\n\n\ndef started_sign_in(request):\n    \"\"\"Send the \"started sign in\" analytics event.\"\"\"\n    core.send_event(StartedSignInEvent(request))\n\n\ndef canceled_sign_in(request):\n    \"\"\"Send the \"canceled sign in\" analytics event.\"\"\"\n    core.send_event(CanceledSignInEvent(request))\n\n\ndef finished_sign_in(request):\n    \"\"\"Send the \"finished sign in\" analytics event.\"\"\"\n    core.send_event(FinishedSignInEvent(request))\n\n\ndef started_sign_out(request):\n    \"\"\"Send the \"started signed out\" analytics event.\"\"\"\n    core.send_event(StartedSignOutEvent(request))\n\n\ndef finished_sign_out(request):\n    \"\"\"Send the \"finished sign out\" analytics event.\"\"\"\n    core.send_event(FinishedSignOutEvent(request))\n", "path": "benefits/oauth/analytics.py"}, {"content": "import logging\n\nfrom django.shortcuts import redirect\nfrom django.urls import reverse\nfrom django.utils.decorators import decorator_from_middleware\n\nfrom benefits.core import session\nfrom benefits.core.middleware import VerifierSessionRequired\nfrom . import analytics, redirects\nfrom .client import oauth\n\n\nlogger = logging.getLogger(__name__)\n\n\nROUTE_AUTH = \"oauth:authorize\"\nROUTE_START = \"eligibility:start\"\nROUTE_CONFIRM = \"eligibility:confirm\"\nROUTE_UNVERIFIED = \"eligibility:unverified\"\nROUTE_POST_LOGOUT = \"oauth:post_logout\"\n\n\n@decorator_from_middleware(VerifierSessionRequired)\ndef login(request):\n    \"\"\"View implementing OIDC authorize_redirect.\"\"\"\n    verifier = session.verifier(request)\n    oauth_client = oauth.create_client(verifier.auth_provider.client_name)\n\n    if not oauth_client:\n        raise Exception(f\"oauth_client not registered: {verifier.auth_provider.client_name}\")\n\n    route = reverse(ROUTE_AUTH)\n    redirect_uri = redirects.generate_redirect_uri(request, route)\n\n    logger.debug(f\"OAuth authorize_redirect with redirect_uri: {redirect_uri}\")\n\n    analytics.started_sign_in(request)\n\n    return oauth_client.authorize_redirect(request, redirect_uri)\n\n\n@decorator_from_middleware(VerifierSessionRequired)\ndef authorize(request):\n    \"\"\"View implementing OIDC token authorization.\"\"\"\n    verifier = session.verifier(request)\n    oauth_client = oauth.create_client(verifier.auth_provider.client_name)\n\n    if not oauth_client:\n        raise Exception(f\"oauth_client not registered: {verifier.auth_provider.client_name}\")\n\n    logger.debug(\"Attempting to authorize OAuth access token\")\n    token = oauth_client.authorize_access_token(request)\n\n    if token is None:\n        logger.warning(\"Could not authorize OAuth access token\")\n        return redirect(ROUTE_START)\n\n    logger.debug(\"OAuth access token authorized\")\n\n    # We store the id_token in the user's session. This is the minimal amount of information needed later to log the user out.\n    id_token = token[\"id_token\"]\n\n    # We store the returned claim in case it can be used later in eligibility verification.\n    verifier_claim = verifier.auth_provider.claim\n    stored_claim = None\n\n    if verifier_claim:\n        userinfo = token.get(\"userinfo\")\n        # the claim comes back in userinfo like { \"claim\": \"True\" | \"False\" }\n        claim_flag = (userinfo.get(verifier_claim) if userinfo else \"false\").lower() == \"true\"\n        # if userinfo contains our claim and the flag is true, store the *claim*\n        stored_claim = verifier_claim if claim_flag else None\n\n    session.update(request, oauth_token=id_token, oauth_claim=stored_claim)\n\n    analytics.finished_sign_in(request)\n\n    return redirect(ROUTE_CONFIRM)\n\n\ndef cancel(request):\n    \"\"\"View implementing cancellation of OIDC authorization.\"\"\"\n\n    analytics.canceled_sign_in(request)\n\n    return redirect(ROUTE_UNVERIFIED)\n\n\n@decorator_from_middleware(VerifierSessionRequired)\ndef logout(request):\n    \"\"\"View implementing OIDC and application sign out.\"\"\"\n    verifier = session.verifier(request)\n    oauth_client = oauth.create_client(verifier.auth_provider.client_name)\n\n    if not oauth_client:\n        raise Exception(f\"oauth_client not registered: {verifier.auth_provider.client_name}\")\n\n    analytics.started_sign_out(request)\n\n    # overwrite the oauth session token, the user is signed out of the app\n    token = session.oauth_token(request)\n    session.logout(request)\n\n    route = reverse(ROUTE_POST_LOGOUT)\n    redirect_uri = redirects.generate_redirect_uri(request, route)\n\n    logger.debug(f\"OAuth end_session_endpoint with redirect_uri: {redirect_uri}\")\n\n    # send the user through the end_session_endpoint, redirecting back to\n    # the post_logout route\n    return redirects.deauthorize_redirect(oauth_client, token, redirect_uri)\n\n\ndef post_logout(request):\n    \"\"\"View routes the user to their origin after sign out.\"\"\"\n\n    analytics.finished_sign_out(request)\n\n    origin = session.origin(request)\n    return redirect(origin)\n", "path": "benefits/oauth/views.py"}]}