From 8b09864f0af9616706947b7aa22dd01aa311a6dd Mon Sep 17 00:00:00 2001 From: "workos-tars[bot]" <269013284+workos-tars[bot]@users.noreply.github.com> Date: Wed, 12 Aug 2026 17:49:55 +0000 Subject: [PATCH 1/2] feat: expose authentication method on action contexts --- lib/workos/action_context.ex | 4 ++++ test/workos/actions_test.exs | 6 ++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/lib/workos/action_context.ex b/lib/workos/action_context.ex index 88c65d9..ac4e4cb 100644 --- a/lib/workos/action_context.ex +++ b/lib/workos/action_context.ex @@ -18,6 +18,7 @@ defmodule WorkOS.ActionContext do defstruct [ :object, :id, + :authentication_method, :ip_address, :user_agent, :device_fingerprint, @@ -32,6 +33,7 @@ defmodule WorkOS.ActionContext do @type t :: %__MODULE__{ object: String.t() | nil, id: String.t() | nil, + authentication_method: WorkOS.AuthenticateResponseAuthenticationMethod.t() | nil, ip_address: String.t() | nil, user_agent: String.t() | nil, device_fingerprint: String.t() | nil, @@ -49,6 +51,8 @@ defmodule WorkOS.ActionContext do %__MODULE__{ object: map["object"], id: map["id"], + authentication_method: + WorkOS.AuthenticateResponseAuthenticationMethod.cast(map["authentication_method"]), ip_address: map["ip_address"], user_agent: map["user_agent"], device_fingerprint: map["device_fingerprint"], diff --git a/test/workos/actions_test.exs b/test/workos/actions_test.exs index 38527b5..0d12b67 100644 --- a/test/workos/actions_test.exs +++ b/test/workos/actions_test.exs @@ -6,7 +6,7 @@ defmodule WorkOS.ActionsTest do alias WorkOS.Webhooks.Signature @secret "actions_secret_123" - @payload ~s({"object":"authentication_action_context","id":"action_01","user":{"object":"user","id":"user_01","email":"test@example.com"},"ip_address":"1.2.3.4","device_fingerprint":"fp_123","issuer":"https://auth.example.com"}) + @payload ~s({"object":"authentication_action_context","id":"action_01","authentication_method":"Password","user":{"object":"user","id":"user_01","email":"test@example.com"},"ip_address":"1.2.3.4","device_fingerprint":"fp_123","issuer":"https://auth.example.com"}) defp signed_header(payload, now_ms) do timestamp = Integer.to_string(now_ms) @@ -44,6 +44,7 @@ defmodule WorkOS.ActionsTest do assert action.object == "authentication_action_context" assert action.id == "action_01" + assert action.authentication_method == :password assert action.user.id == "user_01" assert action.user.email == "test@example.com" assert action.ip_address == "1.2.3.4" @@ -52,7 +53,7 @@ defmodule WorkOS.ActionsTest do test "construct_action deserializes a user_registration request" do payload = - ~s({"object":"user_registration_action_context","id":"action_02","user_data":{"object":"user_data","email":"new@example.com","first_name":"New","last_name":"User","name":null},"ip_address":"5.6.7.8","device_fingerprint":"fp_456"}) + ~s({"object":"user_registration_action_context","id":"action_02","authentication_method":"GoogleOAuth","user_data":{"object":"user_data","email":"new@example.com","first_name":"New","last_name":"User","name":null},"ip_address":"5.6.7.8","device_fingerprint":"fp_456"}) header = signed_header(payload, System.system_time(:millisecond)) @@ -60,6 +61,7 @@ defmodule WorkOS.ActionsTest do WorkOS.Actions.construct_action(payload, header, @secret) assert action.object == "user_registration_action_context" + assert action.authentication_method == :google_oauth assert action.user_data.email == "new@example.com" assert action.user_data.first_name == "New" assert action.user == nil From 717dfd1073a4fda96c4b52003cf3d46f3c776378 Mon Sep 17 00:00:00 2001 From: "Garen J. Torikian" Date: Thu, 13 Aug 2026 09:19:15 -0400 Subject: [PATCH 2/2] fix: document authentication_method as shared and cover nil/unknown paths The ActionContext moduledoc enumerates which fields are common to both context variants, so adding authentication_method left that list understating the shape. This file is hand-maintained precisely because the Actions payload is absent from the OpenAPI spec, making its moduledoc the only documentation of that shape. Route the cast through WorkOS.Cast.enum/2 to match how every other enum field is built (see authenticate_response.ex) and the WorkOS.Cast.nested calls alongside it. Behavior is unchanged; cast/1 already returned nil for nil via its catch-all clause. Both existing payloads gained the field in place, which silently dropped the absent-field coverage they used to provide. Add cases for the nil path and for the lenient caster's unknown-value passthrough, the forward-compatibility behavior that keeps a new server-side method from crashing the SDK. The typespec stays as t() | nil rather than gaining | String.t(): the generated authenticate_response.ex declares the same field the same way with the same lenient caster, and diverging here would make this the only struct in the SDK spelling it differently. --- lib/workos/action_context.ex | 10 +++++++--- test/workos/actions_test.exs | 26 ++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 3 deletions(-) diff --git a/lib/workos/action_context.ex b/lib/workos/action_context.ex index ac4e4cb..68355ca 100644 --- a/lib/workos/action_context.ex +++ b/lib/workos/action_context.ex @@ -11,8 +11,9 @@ defmodule WorkOS.ActionContext do `organization_membership`, `issuer` * `"user_registration_action_context"` — `user_data`, `invitation` - `ip_address`, `user_agent`, and `device_fingerprint` are shared by both - context types; fields specific to the other variant are `nil`. + `authentication_method`, `ip_address`, `user_agent`, and + `device_fingerprint` are shared by both context types; fields specific to + the other variant are `nil`. """ defstruct [ @@ -52,7 +53,10 @@ defmodule WorkOS.ActionContext do object: map["object"], id: map["id"], authentication_method: - WorkOS.AuthenticateResponseAuthenticationMethod.cast(map["authentication_method"]), + WorkOS.Cast.enum( + map["authentication_method"], + &WorkOS.AuthenticateResponseAuthenticationMethod.cast/1 + ), ip_address: map["ip_address"], user_agent: map["user_agent"], device_fingerprint: map["device_fingerprint"], diff --git a/test/workos/actions_test.exs b/test/workos/actions_test.exs index 0d12b67..19bd14d 100644 --- a/test/workos/actions_test.exs +++ b/test/workos/actions_test.exs @@ -67,6 +67,32 @@ defmodule WorkOS.ActionsTest do assert action.user == nil end + test "construct_action leaves authentication_method nil when the field is absent" do + payload = + ~s({"object":"authentication_action_context","id":"action_03","user":{"object":"user","id":"user_03","email":"absent@example.com"},"ip_address":"9.10.11.12"}) + + header = signed_header(payload, System.system_time(:millisecond)) + + assert {:ok, %WorkOS.ActionContext{} = action} = + WorkOS.Actions.construct_action(payload, header, @secret) + + assert action.id == "action_03" + assert action.authentication_method == nil + end + + test "construct_action passes an unknown authentication_method through unchanged" do + payload = + ~s({"object":"authentication_action_context","id":"action_04","authentication_method":"FutureMethod","user":{"object":"user","id":"user_04","email":"future@example.com"},"ip_address":"13.14.15.16"}) + + header = signed_header(payload, System.system_time(:millisecond)) + + assert {:ok, %WorkOS.ActionContext{} = action} = + WorkOS.Actions.construct_action(payload, header, @secret) + + assert action.id == "action_04" + assert action.authentication_method == "FutureMethod" + end + test "sign_response produces a workos-node-compatible Allow response" do now_ms = 1_700_000_000_000