@@ -1248,7 +1248,10 @@ defmodule LightningWeb.CredentialLiveTest do
12481248 button_html = delete_credential_button ( view , project . id ) |> render ( )
12491249
12501250 assert button_html =~
1251- "data-confirm=\" Warning: This credential is in use by the following workflows: #{ workflow_with_credential_1 . name } , #{ workflow_with_credential_2 . name } . If you revoke access to the "#{ project . name } " project, runs for those workflows will probably fail until you provide a new credential. Are you sure you want to revoke access?"
1251+ "data-confirm=\" Warning: This credential is in use by the following workflows:"
1252+
1253+ assert button_html =~
1254+ ". If you revoke access to the "#{ project . name } " project, runs for those workflows will probably fail until you provide a new credential. Are you sure you want to revoke access?"
12521255
12531256 assert button_html =~ workflow_with_credential_1 . name
12541257 assert button_html =~ workflow_with_credential_2 . name
@@ -1391,21 +1394,201 @@ defmodule LightningWeb.CredentialLiveTest do
13911394 :error === assigns [ :oauth_progress ]
13921395 end )
13931396
1394- # After the error state, check the rendered content
13951397 html = view |> element ( "#credential-form-#{ credential . id } " ) |> render ( )
13961398
1397- # Check for 401 error message content
1398- assert html =~ "Your authorization with"
1399- assert html =~ "expired or was revoked"
1399+ assert html =~ "session has expired"
14001400
1401- # The button text for 401 errors is "Sign In Again"
14021401 assert view
14031402 |> element (
14041403 "#credential-form-#{ credential . id } button" ,
14051404 "Sign In Again"
14061405 )
14071406 |> has_element? ( )
14081407 end
1408+
1409+ test "renders reauthorize prompt when refresh token is revoked" ,
1410+ % {
1411+ conn: conn ,
1412+ user: user ,
1413+ token: token
1414+ } do
1415+ oauth_client = insert ( :oauth_client , user: user , userinfo_endpoint: nil )
1416+
1417+ expired_token =
1418+ Map . put ( token , "expires_at" , DateTime . to_unix ( DateTime . utc_now ( ) ) - 3600 )
1419+
1420+ credential =
1421+ insert ( :credential ,
1422+ user: user ,
1423+ schema: "oauth" ,
1424+ oauth_client: oauth_client
1425+ )
1426+ |> with_body ( % {
1427+ name: "main" ,
1428+ body: expired_token
1429+ } )
1430+
1431+ Mox . stub ( Lightning.AuthProviders.OauthHTTPClient.Mock , :call , fn env ,
1432+ _opts ->
1433+ case env . url do
1434+ "http://example.com/oauth2/revoke" ->
1435+ { :ok , % Tesla.Env { status: 200 , body: Jason . encode! ( % { } ) } }
1436+
1437+ "http://example.com/oauth2/token" ->
1438+ { :ok ,
1439+ % Tesla.Env {
1440+ status: 400 ,
1441+ body:
1442+ Jason . encode! ( % {
1443+ "error" => "invalid_grant" ,
1444+ "error_description" => "Token has been expired or revoked."
1445+ } )
1446+ } }
1447+ end
1448+ end )
1449+
1450+ { :ok , view , _html } = live ( conn , ~p" /credentials" , on_error: :raise )
1451+
1452+ open_edit_credential_modal ( view , credential . id )
1453+
1454+ Lightning.ApplicationHelpers . dynamically_absorb_delay ( fn ->
1455+ { _ , assigns } =
1456+ Lightning.LiveViewHelpers . get_component_assigns_by ( view ,
1457+ id: "generic-oauth-component-#{ credential . id } -main"
1458+ )
1459+
1460+ :error === assigns [ :oauth_progress ]
1461+ end )
1462+
1463+ html = view |> element ( "#credential-form-#{ credential . id } " ) |> render ( )
1464+
1465+ assert html =~ "revoked"
1466+ refute html =~ "An error occurred during authentication"
1467+
1468+ assert view
1469+ |> element (
1470+ "#credential-form-#{ credential . id } button" ,
1471+ "Reauthorize"
1472+ )
1473+ |> has_element? ( )
1474+ end
1475+
1476+ test "a failed refresh with a 5xx keeps the transient provider-error message" ,
1477+ % { conn: conn , user: user , token: token } do
1478+ oauth_client = insert ( :oauth_client , user: user , userinfo_endpoint: nil )
1479+
1480+ expired_token =
1481+ Map . put ( token , "expires_at" , DateTime . to_unix ( DateTime . utc_now ( ) ) - 3600 )
1482+
1483+ credential =
1484+ insert ( :credential ,
1485+ user: user ,
1486+ schema: "oauth" ,
1487+ oauth_client: oauth_client
1488+ )
1489+ |> with_body ( % { name: "main" , body: expired_token } )
1490+
1491+ Mox . stub ( Lightning.AuthProviders.OauthHTTPClient.Mock , :call , fn env ,
1492+ _opts ->
1493+ case env . url do
1494+ "http://example.com/oauth2/revoke" ->
1495+ { :ok , % Tesla.Env { status: 200 , body: Jason . encode! ( % { } ) } }
1496+
1497+ "http://example.com/oauth2/token" ->
1498+ { :ok ,
1499+ % Tesla.Env {
1500+ status: 503 ,
1501+ body: Jason . encode! ( % { "error" => "server_error" } )
1502+ } }
1503+ end
1504+ end )
1505+
1506+ { :ok , view , _html } = live ( conn , ~p" /credentials" , on_error: :raise )
1507+
1508+ open_edit_credential_modal ( view , credential . id )
1509+
1510+ Lightning.ApplicationHelpers . dynamically_absorb_delay ( fn ->
1511+ { _ , assigns } =
1512+ Lightning.LiveViewHelpers . get_component_assigns_by ( view ,
1513+ id: "generic-oauth-component-#{ credential . id } -main"
1514+ )
1515+
1516+ :error === assigns [ :oauth_progress ]
1517+ end )
1518+
1519+ html = view |> element ( "#credential-form-#{ credential . id } " ) |> render ( )
1520+
1521+ assert html =~ "technical difficulties"
1522+ refute html =~ "revoked"
1523+ refute html =~ "An error occurred during authentication"
1524+ end
1525+
1526+ test "a code-exchange failure is not treated as a refresh reauthorization" ,
1527+ % { conn: conn , user: user } do
1528+ insert ( :project , project_users: [ % { user: user , role: :owner } ] )
1529+
1530+ oauth_client =
1531+ insert ( :oauth_client ,
1532+ user: user ,
1533+ mandatory_scopes: "" ,
1534+ optional_scopes: ""
1535+ )
1536+
1537+ Mox . stub ( Lightning.AuthProviders.OauthHTTPClient.Mock , :call , fn env ,
1538+ _opts ->
1539+ case env . url do
1540+ "http://example.com/oauth2/token" ->
1541+ { :ok ,
1542+ % Tesla.Env {
1543+ status: 400 ,
1544+ body:
1545+ Jason . encode! ( % {
1546+ "error" => "invalid_grant" ,
1547+ "error_description" => "Bad authorization code."
1548+ } )
1549+ } }
1550+ end
1551+ end )
1552+
1553+ { :ok , view , _html } = live ( conn , ~p" /credentials" , on_error: :raise )
1554+
1555+ open_create_credential_modal ( view )
1556+ view |> select_credential_type ( oauth_client . id )
1557+ view |> click_continue ( )
1558+ view |> fill_credential ( % { name: "My Generic OAuth Credential" } )
1559+
1560+ { _ , component_assigns } =
1561+ Lightning.LiveViewHelpers . get_component_assigns_by ( view ,
1562+ id: "generic-oauth-component-new-main"
1563+ )
1564+
1565+ [ subscription_id , mod , _component_id , _env ] =
1566+ get_decoded_state ( component_assigns [ :authorize_url ] )
1567+
1568+ view |> element ( "#authorize-button" ) |> render_click ( )
1569+
1570+ LightningWeb.OauthCredentialHelper . broadcast_forward (
1571+ subscription_id ,
1572+ mod ,
1573+ id: "generic-oauth-component-new-main" ,
1574+ code: "authcode123" ,
1575+ current_tab: "main"
1576+ )
1577+
1578+ Lightning.ApplicationHelpers . dynamically_absorb_delay ( fn ->
1579+ { _ , assigns } =
1580+ Lightning.LiveViewHelpers . get_component_assigns_by ( view ,
1581+ id: "generic-oauth-component-new-main"
1582+ )
1583+
1584+ :error === assigns [ :oauth_progress ]
1585+ end )
1586+
1587+ html = view |> render ( )
1588+
1589+ assert html =~ "An error occurred during authentication"
1590+ refute html =~ "Refresh Token Revoked"
1591+ end
14091592 end
14101593
14111594 describe "generic oauth credential when flow fails" do
0 commit comments