Skip to content

Commit b162486

Browse files
authored
Merge pull request #529 from workos/generated-url-builders
feat: replace hand-written URL builders with generated ones
1 parent 75b43af commit b162486

5 files changed

Lines changed: 241 additions & 80 deletions

File tree

lib/workos/sso.rb

Lines changed: 73 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
# This file is auto-generated by oagen. Do not edit.
44

55
require "json"
6+
require "uri"
67

78
module WorkOS
89
class SSO
@@ -106,6 +107,74 @@ def delete_connection(
106107
nil
107108
end
108109

110+
# Initiate SSO
111+
# Builds the URL client-side; no HTTP request is made.
112+
# @param provider_scopes [Array<String>, nil] Additional scopes to request from the identity provider. Applicable when using OAuth or OpenID Connect connections.
113+
# @param provider_query_params [Hash{String => String}, nil] Key/value pairs of query parameters to pass to the OAuth provider. Only applicable when using OAuth connections.
114+
# @param client_id [String, nil] The unique identifier of the WorkOS environment client. Defaults to the client's configured client_id.
115+
# @param domain [String, nil] Deprecated. Use `connection` or `organization` instead. Used to initiate SSO for a connection by domain. The domain must be associated with a connection in your WorkOS environment.
116+
# @param provider [WorkOS::Types::SSOProvider, nil] Used to initiate OAuth authentication with various providers.
117+
# @param redirect_uri [String] Where to redirect the user after they complete the authentication process. You must use one of the redirect URIs configured via the [Redirects](https://dashboard.workos.com/redirects) page on the dashboard.
118+
# @param state [String, nil] An optional parameter that can be used to encode arbitrary information to help restore application state between redirects. If included, the redirect URI received from WorkOS will contain the exact `state` that was passed.
119+
# @param connection [String, nil] Used to initiate SSO for a connection. The value should be a WorkOS connection ID. You can persist the WorkOS connection ID with application user or team identifiers. WorkOS will use the connection indicated by the connection parameter to direct the user to the corresponding IdP for authentication.
120+
# @param organization [String, nil] Used to initiate SSO for an organization. The value should be a WorkOS organization ID. You can persist the WorkOS organization ID with application user or team identifiers. WorkOS will use the organization ID to determine the appropriate connection and the IdP to direct the user to for authentication.
121+
# @param domain_hint [String, nil] Can be used to pre-fill the domain field when initiating authentication with Microsoft OAuth or with a Google SAML connection type.
122+
# @param login_hint [String, nil] Can be used to pre-fill the username/email address field of the IdP sign-in page for the user, if you know their username ahead of time. Currently supported for OAuth, OpenID Connect, Okta, Entra ID, and custom SAML connections.
123+
# @param nonce [String, nil] A random string generated by the client that is used to mitigate replay attacks.
124+
# @param prompt [String, nil] If set to `login`, forces re-authentication at the identity provider. For SAML connections this sets `ForceAuthn="true"` in the SAML request.
125+
# @return [String]
126+
def get_authorization_url(
127+
redirect_uri:,
128+
provider_scopes: nil,
129+
provider_query_params: nil,
130+
client_id: nil,
131+
domain: nil,
132+
provider: nil,
133+
state: nil,
134+
connection: nil,
135+
organization: nil,
136+
domain_hint: nil,
137+
login_hint: nil,
138+
nonce: nil,
139+
prompt: nil
140+
)
141+
params = {
142+
"provider_scopes" => provider_scopes,
143+
"provider_query_params" => provider_query_params,
144+
"client_id" => client_id,
145+
"domain" => domain,
146+
"provider" => provider,
147+
"redirect_uri" => redirect_uri,
148+
"state" => state,
149+
"connection" => connection,
150+
"organization" => organization,
151+
"domain_hint" => domain_hint,
152+
"login_hint" => login_hint,
153+
"nonce" => nonce,
154+
"prompt" => prompt
155+
}.compact
156+
params["provider_scopes"] = provider_scopes.join(",") unless provider_scopes.nil?
157+
params["provider_query_params"] = JSON.generate(provider_query_params) unless provider_query_params.nil?
158+
params["response_type"] = "code"
159+
params["client_id"] = @client.client_id if !params.key?("client_id") && !@client.client_id.nil?
160+
uri = URI.join(@client.base_url, "/sso/authorize")
161+
uri.query = URI.encode_www_form(params) unless params.empty?
162+
uri.to_s
163+
end
164+
165+
# Logout Redirect
166+
# Builds the URL client-side; no HTTP request is made.
167+
# @param token [String] The logout token returned from the [Logout Authorize](https://workos.com/docs/reference/sso/logout/authorize) endpoint.
168+
# @return [String]
169+
def get_logout_url(token:)
170+
params = {
171+
"token" => token
172+
}
173+
uri = URI.join(@client.base_url, "/sso/logout")
174+
uri.query = URI.encode_www_form(params) unless params.empty?
175+
uri.to_s
176+
end
177+
109178
# Logout Authorize
110179
# @param profile_id [String] The unique ID of the profile to log out.
111180
# @param request_options [Hash] (see WorkOS::Types::RequestOptions)
@@ -171,32 +240,10 @@ def get_profile_and_token(
171240
end
172241

173242
# @oagen-ignore-start — non-spec helpers (hand-maintained)
174-
# H14 — Build an SSO authorization URL (client-side, no HTTP call).
175-
# Overrides the generated method which incorrectly hits the API.
176-
def get_authorization_url(redirect_uri:, client_id: nil, state: nil, connection: nil,
177-
organization: nil, provider: nil, domain_hint: nil,
178-
login_hint: nil, nonce: nil, provider_scopes: nil,
179-
provider_query_params: nil, **)
180-
cid = client_id || @client.client_id
181-
raise ArgumentError, "client_id is required (set on Client or pass explicitly)" if cid.nil? || cid.empty?
182-
params = {
183-
"client_id" => cid,
184-
"redirect_uri" => redirect_uri,
185-
"response_type" => "code",
186-
"state" => state,
187-
"connection" => connection,
188-
"organization" => organization,
189-
"provider" => provider,
190-
"domain_hint" => domain_hint,
191-
"login_hint" => login_hint,
192-
"nonce" => nonce
193-
}.compact
194-
params["provider_scopes"] = Array(provider_scopes).join(",") if provider_scopes
195-
if provider_query_params.is_a?(Hash) && !provider_query_params.empty?
196-
params["provider_query_params"] = JSON.generate(provider_query_params)
197-
end
198-
build_url("/sso/authorize", params)
199-
end
243+
# H14 (sso_authorization_url) is provided by the generated
244+
# `get_authorization_url` url-builder method, which accepts an optional
245+
# per-call `client_id` override falling back to the client's configured
246+
# value; no hand-maintained override is needed here.
200247

201248
# H15 — SSO authorization URL with auto-generated PKCE pair + state.
202249
# Returns [url, code_verifier, state].

lib/workos/user_management.rb

Lines changed: 90 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
# This file is auto-generated by oagen. Do not edit.
44

55
require "json"
6+
require "uri"
67

78
module WorkOS
89
class UserManagement
@@ -515,6 +516,70 @@ def authenticate_with_radar_sms_challenge(
515516
WorkOS::AuthenticateResponse.new(response.body)
516517
end
517518

519+
# Get an authorization URL
520+
# Builds the URL client-side; no HTTP request is made.
521+
# @param code_challenge_method [String, nil] The only valid PKCE code challenge method is `"S256"`. Required when specifying a `code_challenge`.
522+
# @param code_challenge [String, nil] Code challenge derived from the code verifier used for the PKCE flow.
523+
# @param domain_hint [String, nil] A domain hint for SSO connection lookup.
524+
# @param connection_id [String, nil] The ID of an SSO connection to use for authentication.
525+
# @param provider_query_params [Hash{String => String}, nil] Key/value pairs of query parameters to pass to the OAuth provider.
526+
# @param provider_scopes [Array<String>, nil] Additional OAuth scopes to request from the identity provider.
527+
# @param invitation_token [String, nil] A token representing a user invitation to redeem during authentication.
528+
# @param max_age [Integer, nil] Maximum allowable elapsed time, in seconds, since the user last actively authenticated. If the last authentication is older than this value, the user is prompted to re-authenticate; a value of `0` forces re-authentication. Only supported when the provider is `authkit`.
529+
# @param screen_hint [WorkOS::Types::UserManagementAuthenticationScreenHint, nil] Used to specify which screen to display when the provider is `authkit`.
530+
# @param login_hint [String, nil] A hint to the authorization server about the login identifier the user might use.
531+
# @param provider [WorkOS::Types::UserManagementAuthenticationProvider, nil] The OAuth provider to authenticate with (e.g., GoogleOAuth, MicrosoftOAuth, GitHubOAuth).
532+
# @param prompt [String, nil] Controls the authentication flow behavior for the user.
533+
# @param state [String, nil] An opaque value used to maintain state between the request and the callback.
534+
# @param organization_id [String, nil] The ID of the organization to authenticate the user against.
535+
# @param redirect_uri [String] The callback URI where the authorization code will be sent after authentication.
536+
# @param client_id [String, nil] The unique identifier of the WorkOS environment client. Defaults to the client's configured client_id.
537+
# @return [String]
538+
def get_authorization_url(
539+
redirect_uri:,
540+
code_challenge_method: nil,
541+
code_challenge: nil,
542+
domain_hint: nil,
543+
connection_id: nil,
544+
provider_query_params: nil,
545+
provider_scopes: nil,
546+
invitation_token: nil,
547+
max_age: nil,
548+
screen_hint: nil,
549+
login_hint: nil,
550+
provider: nil,
551+
prompt: nil,
552+
state: nil,
553+
organization_id: nil,
554+
client_id: nil
555+
)
556+
params = {
557+
"code_challenge_method" => code_challenge_method,
558+
"code_challenge" => code_challenge,
559+
"domain_hint" => domain_hint,
560+
"connection_id" => connection_id,
561+
"provider_query_params" => provider_query_params,
562+
"provider_scopes" => provider_scopes,
563+
"invitation_token" => invitation_token,
564+
"max_age" => max_age,
565+
"screen_hint" => screen_hint,
566+
"login_hint" => login_hint,
567+
"provider" => provider,
568+
"prompt" => prompt,
569+
"state" => state,
570+
"organization_id" => organization_id,
571+
"redirect_uri" => redirect_uri,
572+
"client_id" => client_id
573+
}.compact
574+
params["provider_query_params"] = JSON.generate(provider_query_params) unless provider_query_params.nil?
575+
params["provider_scopes"] = provider_scopes.join(",") unless provider_scopes.nil?
576+
params["response_type"] = "code"
577+
params["client_id"] = @client.client_id if !params.key?("client_id") && !@client.client_id.nil?
578+
uri = URI.join(@client.base_url, "/user_management/authorize")
579+
uri.query = URI.encode_www_form(params) unless params.empty?
580+
uri.to_s
581+
end
582+
518583
# Get device authorization URL
519584
# @param client_id [String] The WorkOS client ID for your application.
520585
# @param request_options [Hash] (see WorkOS::Types::RequestOptions)
@@ -592,6 +657,24 @@ def get_radar_challenge(
592657
result
593658
end
594659

660+
# Logout
661+
# Builds the URL client-side; no HTTP request is made.
662+
# @param session_id [String] The ID of the session. This can be extracted from the `sid` claim of the access token.
663+
# @param return_to [String, nil] The URL to redirect the user to after logout.
664+
# @return [String]
665+
def get_logout_url(
666+
session_id:,
667+
return_to: nil
668+
)
669+
params = {
670+
"session_id" => session_id,
671+
"return_to" => return_to
672+
}.compact
673+
uri = URI.join(@client.base_url, "/user_management/sessions/logout")
674+
uri.query = URI.encode_www_form(params) unless params.empty?
675+
uri.to_s
676+
end
677+
595678
# Revoke Session
596679
# @param session_id [String] The ID of the session to revoke. This can be extracted from the `sid` claim of the access token.
597680
# @param request_options [Hash] (see WorkOS::Types::RequestOptions)
@@ -1690,32 +1773,10 @@ def get_jwks_url(client_id: nil)
16901773
URI.join(base, "/sso/jwks/#{WorkOS::Util.encode_path(cid)}").to_s
16911774
end
16921775

1693-
# H09 — Build an AuthKit authorization URL (client-side, no HTTP call).
1694-
# Overrides the generated get_authorization_url which hits the API.
1695-
def get_authorization_url(redirect_uri:, client_id: nil, provider: nil, connection_id: nil,
1696-
organization_id: nil, domain_hint: nil, login_hint: nil,
1697-
state: nil, screen_hint: nil, code_challenge: nil,
1698-
code_challenge_method: nil, prompt: nil, **)
1699-
cid = client_id || @client.client_id
1700-
raise ArgumentError, "client_id is required (set on Client or pass explicitly)" if cid.nil? || cid.empty?
1701-
raise ArgumentError, "provider, connection_id, or organization_id required" if provider.nil? && connection_id.nil? && organization_id.nil?
1702-
params = {
1703-
"client_id" => cid,
1704-
"redirect_uri" => redirect_uri,
1705-
"response_type" => "code",
1706-
"provider" => provider,
1707-
"connection_id" => connection_id,
1708-
"organization_id" => organization_id,
1709-
"domain_hint" => domain_hint,
1710-
"login_hint" => login_hint,
1711-
"state" => state,
1712-
"screen_hint" => screen_hint,
1713-
"code_challenge" => code_challenge,
1714-
"code_challenge_method" => code_challenge_method,
1715-
"prompt" => prompt
1716-
}.compact
1717-
build_url("/user_management/authorize", params)
1718-
end
1776+
# H09 (authkit_authorization_url) is provided by the generated
1777+
# `get_authorization_url` url-builder method, which accepts an optional
1778+
# per-call `client_id` override falling back to the client's configured
1779+
# value; no hand-maintained override is needed here.
17191780

17201781
# H10 — AuthKit authorization URL with auto-generated PKCE + state.
17211782
# Returns [url, code_verifier, state].
@@ -1773,24 +1834,9 @@ def authorize_device(client_id: nil, request_options: {})
17731834
# `authenticate_with_device_code` method (wraps /user_management/authenticate);
17741835
# no hand-maintained override is needed here.
17751836

1776-
# Build the AuthKit logout redirect URL (client-side, no HTTP call).
1777-
# @param session_id [String] The session ID (from the `sid` claim of the access token).
1778-
# @param return_to [String, nil] URL to redirect the user to after session revocation.
1779-
# @return [String]
1780-
def get_logout_url(session_id:, return_to: nil)
1781-
params = {"session_id" => session_id}
1782-
params["return_to"] = return_to if return_to
1783-
build_url("/user_management/sessions/logout", params)
1784-
end
1785-
1786-
private
1787-
1788-
def build_url(path, params)
1789-
base = @client.base_url
1790-
uri = URI.join(base, path)
1791-
uri.query = URI.encode_www_form(params)
1792-
uri.to_s
1793-
end
1837+
# The AuthKit logout redirect URL is provided by the generated
1838+
# `get_logout_url` url-builder method; no hand-maintained override is
1839+
# needed here.
17941840
# @oagen-ignore-end
17951841
end
17961842
end

rbi/workos/sso.rbi

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,32 @@ module WorkOS
4040
end
4141
def delete_connection(id:, request_options:); end
4242

43+
sig do
44+
params(
45+
redirect_uri: String,
46+
provider_scopes: T.nilable(T::Array[String]),
47+
provider_query_params: T.nilable(T::Hash[String, String]),
48+
client_id: T.nilable(String),
49+
domain: T.nilable(String),
50+
provider: T.nilable(String),
51+
state: T.nilable(String),
52+
connection: T.nilable(String),
53+
organization: T.nilable(String),
54+
domain_hint: T.nilable(String),
55+
login_hint: T.nilable(String),
56+
nonce: T.nilable(String),
57+
prompt: T.nilable(String)
58+
).returns(String)
59+
end
60+
def get_authorization_url(redirect_uri:, provider_scopes:, provider_query_params:, client_id:, domain:, provider:, state:, connection:, organization:, domain_hint:, login_hint:, nonce:, prompt:); end
61+
62+
sig do
63+
params(
64+
token: String
65+
).returns(String)
66+
end
67+
def get_logout_url(token:); end
68+
4369
sig do
4470
params(
4571
profile_id: String,

rbi/workos/user_management.rbi

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,28 @@ module WorkOS
6262
end
6363
def create_authenticate(client_id:, grant_type:, code:, client_secret:, code_verifier:, invitation_token:, ip_address:, device_id:, user_agent:, signals_id:, request_options:); end
6464

65+
sig do
66+
params(
67+
redirect_uri: String,
68+
code_challenge_method: T.nilable(String),
69+
code_challenge: T.nilable(String),
70+
domain_hint: T.nilable(String),
71+
connection_id: T.nilable(String),
72+
provider_query_params: T.nilable(T::Hash[String, String]),
73+
provider_scopes: T.nilable(T::Array[String]),
74+
invitation_token: T.nilable(String),
75+
max_age: T.nilable(Integer),
76+
screen_hint: T.nilable(String),
77+
login_hint: T.nilable(String),
78+
provider: T.nilable(String),
79+
prompt: T.nilable(String),
80+
state: T.nilable(String),
81+
organization_id: T.nilable(String),
82+
client_id: T.nilable(String)
83+
).returns(String)
84+
end
85+
def get_authorization_url(redirect_uri:, code_challenge_method:, code_challenge:, domain_hint:, connection_id:, provider_query_params:, provider_scopes:, invitation_token:, max_age:, screen_hint:, login_hint:, provider:, prompt:, state:, organization_id:, client_id:); end
86+
6587
sig do
6688
params(
6789
client_id: String,
@@ -90,6 +112,14 @@ module WorkOS
90112
end
91113
def get_radar_challenge(id:, request_options:); end
92114

115+
sig do
116+
params(
117+
session_id: String,
118+
return_to: T.nilable(String)
119+
).returns(String)
120+
end
121+
def get_logout_url(session_id:, return_to:); end
122+
93123
sig do
94124
params(
95125
session_id: String,

0 commit comments

Comments
 (0)