From 7be8e6499c912ea8ec7ca59e860b32862bdfc1bb Mon Sep 17 00:00:00 2001 From: Lyle Schemmerling Date: Wed, 17 Sep 2025 16:47:58 -0600 Subject: [PATCH 1/9] new optional tenant id param added (breaking) --- src/main/api/approveDevice.json | 8 ++++++++ src/main/api/clientCredentialsGrant.json | 8 ++++++++ src/main/api/exchangeOAuthCodeForAccessToken.json | 8 ++++++++ .../api/exchangeOAuthCodeForAccessTokenUsingPKCE.json | 8 ++++++++ src/main/api/exchangeRefreshTokenForAccessToken.json | 8 ++++++++ .../api/exchangeUserCredentialsForAccessToken.json | 8 ++++++++ src/main/api/introspectAccessToken.json | 8 ++++++++ .../api/introspectClientCredentialsAccessToken.json | 8 ++++++++ src/main/api/retrieveUserCode.json | 9 +++++++++ src/main/api/retrieveUserCodeUsingAPIKey.json | 9 +++++++++ src/main/api/retrieveUserInfoFromAccessToken.json | 9 +++++++++ src/main/api/validateDevice.json | 9 +++++++++ src/main/client/java.client.ftl | 10 +++++++++- 13 files changed, 109 insertions(+), 1 deletion(-) diff --git a/src/main/api/approveDevice.json b/src/main/api/approveDevice.json index a61f7ed..315a29a 100644 --- a/src/main/api/approveDevice.json +++ b/src/main/api/approveDevice.json @@ -41,6 +41,14 @@ "type": "form", "parameterName": "user_code", "javaType": "String" + }, + { + "name": "tenantId", + "comments": [ + "(Optional) The Id of the tenant to use for this request." + ], + "type": "form", + "javaType": "UUID" } ] } diff --git a/src/main/api/clientCredentialsGrant.json b/src/main/api/clientCredentialsGrant.json index ff03213..b2bc3f9 100644 --- a/src/main/api/clientCredentialsGrant.json +++ b/src/main/api/clientCredentialsGrant.json @@ -44,6 +44,14 @@ ], "type": "form", "javaType": "String" + }, + { + "name": "tenantId", + "comments": [ + "(Optional) The Id of the tenant to use for this request." + ], + "type": "form", + "javaType": "UUID" } ] } diff --git a/src/main/api/exchangeOAuthCodeForAccessToken.json b/src/main/api/exchangeOAuthCodeForAccessToken.json index 6cb0b2e..1872e35 100644 --- a/src/main/api/exchangeOAuthCodeForAccessToken.json +++ b/src/main/api/exchangeOAuthCodeForAccessToken.json @@ -52,6 +52,14 @@ ], "type": "form", "javaType": "String" + }, + { + "name": "tenantId", + "comments": [ + "(Optional) The Id of the tenant to use for this request." + ], + "type": "form", + "javaType": "UUID" } ] } diff --git a/src/main/api/exchangeOAuthCodeForAccessTokenUsingPKCE.json b/src/main/api/exchangeOAuthCodeForAccessTokenUsingPKCE.json index e2eba21..2497d97 100644 --- a/src/main/api/exchangeOAuthCodeForAccessTokenUsingPKCE.json +++ b/src/main/api/exchangeOAuthCodeForAccessTokenUsingPKCE.json @@ -60,6 +60,14 @@ ], "type": "form", "javaType": "String" + }, + { + "name": "tenantId", + "comments": [ + "(Optional) The Id of the tenant to use for this request." + ], + "type": "form", + "javaType": "UUID" } ] } diff --git a/src/main/api/exchangeRefreshTokenForAccessToken.json b/src/main/api/exchangeRefreshTokenForAccessToken.json index 94a9cae..53df703 100644 --- a/src/main/api/exchangeRefreshTokenForAccessToken.json +++ b/src/main/api/exchangeRefreshTokenForAccessToken.json @@ -60,6 +60,14 @@ ], "type": "form", "javaType": "String" + }, + { + "name": "tenantId", + "comments": [ + "(Optional) The Id of the tenant to use for this request. Required if the request is for a universal application." + ], + "type": "form", + "javaType": "UUID" } ] } diff --git a/src/main/api/exchangeUserCredentialsForAccessToken.json b/src/main/api/exchangeUserCredentialsForAccessToken.json index e629890..57427d7 100644 --- a/src/main/api/exchangeUserCredentialsForAccessToken.json +++ b/src/main/api/exchangeUserCredentialsForAccessToken.json @@ -68,6 +68,14 @@ ], "type": "form", "javaType": "String" + }, + { + "name": "tenantId", + "comments": [ + "(Optional) The Id of the tenant to use for this request." + ], + "type": "form", + "javaType": "UUID" } ] } diff --git a/src/main/api/introspectAccessToken.json b/src/main/api/introspectAccessToken.json index eca940d..fea4ede 100644 --- a/src/main/api/introspectAccessToken.json +++ b/src/main/api/introspectAccessToken.json @@ -24,6 +24,14 @@ ], "type": "form", "javaType": "String" + }, + { + "name": "tenantId", + "comments": [ + "(Optional) The Id of the tenant to use for this request." + ], + "type": "form", + "javaType": "UUID" } ] } diff --git a/src/main/api/introspectClientCredentialsAccessToken.json b/src/main/api/introspectClientCredentialsAccessToken.json index 7a538ca..a303e76 100644 --- a/src/main/api/introspectClientCredentialsAccessToken.json +++ b/src/main/api/introspectClientCredentialsAccessToken.json @@ -16,6 +16,14 @@ ], "type": "form", "javaType": "String" + }, + { + "name": "tenantId", + "comments": [ + "(Optional) The Id of the tenant to use for this request." + ], + "type": "form", + "javaType": "UUID" } ] } diff --git a/src/main/api/retrieveUserCode.json b/src/main/api/retrieveUserCode.json index 7fdf7e8..377d89e 100644 --- a/src/main/api/retrieveUserCode.json +++ b/src/main/api/retrieveUserCode.json @@ -37,6 +37,15 @@ "type": "form", "parameterName": "user_code", "javaType": "String" + }, + { + "name": "tenantId", + "comments": [ + "(Optional) The Id of the tenant to use for this request." + ], + "type": "urlParameter", + "parameterName": "tenantId", + "javaType": "UUID" } ] } diff --git a/src/main/api/retrieveUserCodeUsingAPIKey.json b/src/main/api/retrieveUserCodeUsingAPIKey.json index a55f6bb..a336f1d 100644 --- a/src/main/api/retrieveUserCodeUsingAPIKey.json +++ b/src/main/api/retrieveUserCodeUsingAPIKey.json @@ -21,6 +21,15 @@ "type": "form", "parameterName": "user_code", "javaType": "String" + }, + { + "name": "tenantId", + "comments": [ + "(Optional) The Id of the tenant to use for this request." + ], + "type": "urlParameter", + "parameterName": "tenantId", + "javaType": "UUID" } ] } diff --git a/src/main/api/retrieveUserInfoFromAccessToken.json b/src/main/api/retrieveUserInfoFromAccessToken.json index 7bccd07..305dced 100644 --- a/src/main/api/retrieveUserInfoFromAccessToken.json +++ b/src/main/api/retrieveUserInfoFromAccessToken.json @@ -17,6 +17,15 @@ ], "type": "notUsed", "javaType": "String" + }, + { + "name": "tenantId", + "comments": [ + "(Optional) The Id of the tenant to use for this request." + ], + "type": "urlParameter", + "parameterName": "tenantId", + "javaType": "UUID" } ] } diff --git a/src/main/api/validateDevice.json b/src/main/api/validateDevice.json index f47c7a6..3c25cde 100644 --- a/src/main/api/validateDevice.json +++ b/src/main/api/validateDevice.json @@ -27,6 +27,15 @@ "type": "urlParameter", "parameterName": "client_id", "javaType": "String" + }, + { + "name": "tenantId", + "comments": [ + "(Optional) The Id of the tenant to use for this request." + ], + "type": "urlParameter", + "parameterName": "tenantId", + "javaType": "UUID" } ] } diff --git a/src/main/client/java.client.ftl b/src/main/client/java.client.ftl index be87944..f04382c 100644 --- a/src/main/client/java.client.ftl +++ b/src/main/client/java.client.ftl @@ -363,8 +363,16 @@ public class FusionAuthClient { [#if formPost] Map> parameters = new HashMap<>(); [#list api.params![] as param] + [#assign pval = param.name /] [#if param.type == "form"] - parameters.put("${param.name}", Arrays.asList(${(param.constant?? && param.constant)?then("\""+param.value+"\"", param.name)})); + [#if param.constant?? && param.constant] + [#assign pval = "\""+param.value+"\"" /] + [#else] + [#if param.javaType != "String"] + [#assign pval = "\"\" + ${param.name}" /] + [/#if] + [/#if] + parameters.put("${param.name}", Arrays.asList(${pval})); [/#if] [/#list] [/#if] From 68acca6ce3b39f6b117e09b64fae9f8c9b0abf2d Mon Sep 17 00:00:00 2001 From: Lyle Schemmerling Date: Tue, 23 Sep 2025 12:17:30 -0600 Subject: [PATCH 2/9] validate and libs --- src/main/api/approveDevice.json | 8 ---- src/main/api/approveDeviceUsingRequest.json | 20 ++++++++++ src/main/api/clientCredentialsGrant.json | 8 ---- .../clientCredentialsGrantUsingRequest.json | 21 +++++++++++ src/main/api/deviceAuthorize.json | 37 +++++++++++++++++++ src/main/api/deviceAuthorizeUsingRequest.json | 21 +++++++++++ .../api/exchangeOAuthCodeForAccessToken.json | 8 ---- ...hangeOAuthCodeForAccessTokenUsingPKCE.json | 8 ---- ...deForAccessTokenUsingPKCEUsingRequest.json | 22 +++++++++++ ...geOAuthCodeForAccessTokenUsingRequest.json | 22 +++++++++++ .../exchangeRefreshTokenForAccessToken.json | 8 ---- ...efreshTokenForAccessTokenUsingRequest.json | 22 +++++++++++ ...exchangeUserCredentialsForAccessToken.json | 8 ---- ...CredentialsForAccessTokenUsingRequest.json | 22 +++++++++++ src/main/api/introspectAccessToken.json | 8 ---- .../introspectAccessTokenUsingRequest.json | 21 +++++++++++ ...ntrospectClientCredentialsAccessToken.json | 8 ---- ...entCredentialsAccessTokenUsingRequest.json | 21 +++++++++++ src/main/api/retrieveUserCode.json | 9 ----- src/main/api/retrieveUserCodeUsingAPIKey.json | 9 ----- ...trieveUserCodeUsingAPIKeyUsingRequest.json | 25 +++++++++++++ .../api/retrieveUserCodeUsingRequest.json | 23 ++++++++++++ src/main/api/validateDevice.json | 9 ----- src/main/api/validateDeviceUsingRequest.json | 22 +++++++++++ src/main/client/java.client.ftl | 11 ++++++ 25 files changed, 310 insertions(+), 91 deletions(-) create mode 100644 src/main/api/approveDeviceUsingRequest.json create mode 100644 src/main/api/clientCredentialsGrantUsingRequest.json create mode 100644 src/main/api/deviceAuthorize.json create mode 100644 src/main/api/deviceAuthorizeUsingRequest.json create mode 100644 src/main/api/exchangeOAuthCodeForAccessTokenUsingPKCEUsingRequest.json create mode 100644 src/main/api/exchangeOAuthCodeForAccessTokenUsingRequest.json create mode 100644 src/main/api/exchangeRefreshTokenForAccessTokenUsingRequest.json create mode 100644 src/main/api/exchangeUserCredentialsForAccessTokenUsingRequest.json create mode 100644 src/main/api/introspectAccessTokenUsingRequest.json create mode 100644 src/main/api/introspectClientCredentialsAccessTokenUsingRequest.json create mode 100644 src/main/api/retrieveUserCodeUsingAPIKeyUsingRequest.json create mode 100644 src/main/api/retrieveUserCodeUsingRequest.json create mode 100644 src/main/api/validateDeviceUsingRequest.json diff --git a/src/main/api/approveDevice.json b/src/main/api/approveDevice.json index 315a29a..a61f7ed 100644 --- a/src/main/api/approveDevice.json +++ b/src/main/api/approveDevice.json @@ -41,14 +41,6 @@ "type": "form", "parameterName": "user_code", "javaType": "String" - }, - { - "name": "tenantId", - "comments": [ - "(Optional) The Id of the tenant to use for this request." - ], - "type": "form", - "javaType": "UUID" } ] } diff --git a/src/main/api/approveDeviceUsingRequest.json b/src/main/api/approveDeviceUsingRequest.json new file mode 100644 index 0000000..14e47ff --- /dev/null +++ b/src/main/api/approveDeviceUsingRequest.json @@ -0,0 +1,20 @@ +{ + "uri": "/oauth2/device/approve", + "comments": [ + "Approve a device grant." + ], + "method": "post", + "methodName": "approveDeviceWithRequest", + "successResponse": "DeviceApprovalResponse", + "errorResponse": "Errors", + "params": [ + { + "name": "request", + "comments": [ + "The request object containing the device approval information and optional tenantId." + ], + "type": "body", + "javaType": "DeviceApprovalRequest" + } + ] +} diff --git a/src/main/api/clientCredentialsGrant.json b/src/main/api/clientCredentialsGrant.json index b2bc3f9..ff03213 100644 --- a/src/main/api/clientCredentialsGrant.json +++ b/src/main/api/clientCredentialsGrant.json @@ -44,14 +44,6 @@ ], "type": "form", "javaType": "String" - }, - { - "name": "tenantId", - "comments": [ - "(Optional) The Id of the tenant to use for this request." - ], - "type": "form", - "javaType": "UUID" } ] } diff --git a/src/main/api/clientCredentialsGrantUsingRequest.json b/src/main/api/clientCredentialsGrantUsingRequest.json new file mode 100644 index 0000000..66cda12 --- /dev/null +++ b/src/main/api/clientCredentialsGrantUsingRequest.json @@ -0,0 +1,21 @@ +{ + "uri": "/oauth2/token", + "comments": [ + "Make a Client Credentials grant request to obtain an access token." + ], + "method": "post", + "methodName": "clientCredentialsGrantWithRequest", + "successResponse": "AccessToken", + "errorResponse": "OAuthError", + "anonymous": true, + "params": [ + { + "name": "request", + "comments": [ + "The client credentials grant request containing client authentication, scope and optional tenantId." + ], + "type": "body", + "javaType": "ClientCredentialsGrantRequest" + } + ] +} diff --git a/src/main/api/deviceAuthorize.json b/src/main/api/deviceAuthorize.json new file mode 100644 index 0000000..a3c63db --- /dev/null +++ b/src/main/api/deviceAuthorize.json @@ -0,0 +1,37 @@ +{ + "uri": "/oauth2/device_authorize", + "comments": [ + "Start the Device Authorization flow using form-encoded parameters" + ], + "method": "post", + "methodName": "deviceAuthorize", + "successResponse": "DeviceResponse", + "errorResponse": "OAuthError", + "anonymous": true, + "params": [ + { + "name": "client_id", + "comments": [ + "The unique client identifier. The client Id is the Id of the FusionAuth Application in which you are attempting to authenticate." + ], + "type": "form", + "javaType": "String" + }, + { + "name": "client_secret", + "comments": [ + "(Optional) The client secret. This value may optionally be provided in the request body instead of the Authorization header." + ], + "type": "form", + "javaType": "String" + }, + { + "name": "scope", + "comments": [ + "(Optional) A space-delimited string of the requested scopes. Defaults to all scopes configured in the Application's OAuth configuration." + ], + "type": "form", + "javaType": "String" + } + ] +} diff --git a/src/main/api/deviceAuthorizeUsingRequest.json b/src/main/api/deviceAuthorizeUsingRequest.json new file mode 100644 index 0000000..ce22219 --- /dev/null +++ b/src/main/api/deviceAuthorizeUsingRequest.json @@ -0,0 +1,21 @@ +{ + "uri": "/oauth2/device_authorize", + "comments": [ + "Start the Device Authorization flow using a request body" + ], + "method": "post", + "methodName": "deviceAuthorizeWithRequest", + "successResponse": "DeviceResponse", + "errorResponse": "OAuthError", + "anonymous": true, + "params": [ + { + "name": "request", + "comments": [ + "The device authorization request containing client authentication, scope, and optional device metadata." + ], + "type": "body", + "javaType": "DeviceAuthorizationRequest" + } + ] +} \ No newline at end of file diff --git a/src/main/api/exchangeOAuthCodeForAccessToken.json b/src/main/api/exchangeOAuthCodeForAccessToken.json index 1872e35..6cb0b2e 100644 --- a/src/main/api/exchangeOAuthCodeForAccessToken.json +++ b/src/main/api/exchangeOAuthCodeForAccessToken.json @@ -52,14 +52,6 @@ ], "type": "form", "javaType": "String" - }, - { - "name": "tenantId", - "comments": [ - "(Optional) The Id of the tenant to use for this request." - ], - "type": "form", - "javaType": "UUID" } ] } diff --git a/src/main/api/exchangeOAuthCodeForAccessTokenUsingPKCE.json b/src/main/api/exchangeOAuthCodeForAccessTokenUsingPKCE.json index 2497d97..e2eba21 100644 --- a/src/main/api/exchangeOAuthCodeForAccessTokenUsingPKCE.json +++ b/src/main/api/exchangeOAuthCodeForAccessTokenUsingPKCE.json @@ -60,14 +60,6 @@ ], "type": "form", "javaType": "String" - }, - { - "name": "tenantId", - "comments": [ - "(Optional) The Id of the tenant to use for this request." - ], - "type": "form", - "javaType": "UUID" } ] } diff --git a/src/main/api/exchangeOAuthCodeForAccessTokenUsingPKCEUsingRequest.json b/src/main/api/exchangeOAuthCodeForAccessTokenUsingPKCEUsingRequest.json new file mode 100644 index 0000000..2d0bfe3 --- /dev/null +++ b/src/main/api/exchangeOAuthCodeForAccessTokenUsingPKCEUsingRequest.json @@ -0,0 +1,22 @@ +{ + "uri": "/oauth2/token", + "comments": [ + "Exchanges an OAuth authorization code and code_verifier for an access token.", + "Makes a request to the Token endpoint to exchange the authorization code returned from the Authorize endpoint and a code_verifier for an access token." + ], + "method": "post", + "methodName": "exchangeOAuthCodeForAccessTokenUsingPKCEWithRequest", + "successResponse": "AccessToken", + "errorResponse": "OAuthError", + "anonymous": true, + "params": [ + { + "name": "request", + "comments": [ + "The PKCE OAuth code access token exchange request." + ], + "type": "body", + "javaType": "OAuthCodePKCEAccessTokenRequest" + } + ] +} diff --git a/src/main/api/exchangeOAuthCodeForAccessTokenUsingRequest.json b/src/main/api/exchangeOAuthCodeForAccessTokenUsingRequest.json new file mode 100644 index 0000000..50f1336 --- /dev/null +++ b/src/main/api/exchangeOAuthCodeForAccessTokenUsingRequest.json @@ -0,0 +1,22 @@ +{ + "uri": "/oauth2/token", + "comments": [ + "Exchanges an OAuth authorization code for an access token.", + "Makes a request to the Token endpoint to exchange the authorization code returned from the Authorize endpoint for an access token." + ], + "method": "post", + "methodName": "exchangeOAuthCodeForAccessTokenWithRequest", + "successResponse": "AccessToken", + "errorResponse": "OAuthError", + "anonymous": true, + "params": [ + { + "name": "request", + "comments": [ + "The OAuth code access token exchange request." + ], + "type": "body", + "javaType": "OAuthCodeAccessTokenRequest" + } + ] +} diff --git a/src/main/api/exchangeRefreshTokenForAccessToken.json b/src/main/api/exchangeRefreshTokenForAccessToken.json index 53df703..94a9cae 100644 --- a/src/main/api/exchangeRefreshTokenForAccessToken.json +++ b/src/main/api/exchangeRefreshTokenForAccessToken.json @@ -60,14 +60,6 @@ ], "type": "form", "javaType": "String" - }, - { - "name": "tenantId", - "comments": [ - "(Optional) The Id of the tenant to use for this request. Required if the request is for a universal application." - ], - "type": "form", - "javaType": "UUID" } ] } diff --git a/src/main/api/exchangeRefreshTokenForAccessTokenUsingRequest.json b/src/main/api/exchangeRefreshTokenForAccessTokenUsingRequest.json new file mode 100644 index 0000000..840373b --- /dev/null +++ b/src/main/api/exchangeRefreshTokenForAccessTokenUsingRequest.json @@ -0,0 +1,22 @@ +{ + "uri": "/oauth2/token", + "comments": [ + "Exchange a Refresh Token for an Access Token.", + "If you will be using the Refresh Token Grant, you will make a request to the Token endpoint to exchange the user’s refresh token for an access token." + ], + "method": "post", + "methodName": "exchangeRefreshTokenForAccessTokenWithRequest", + "successResponse": "AccessToken", + "errorResponse": "OAuthError", + "anonymous": true, + "params": [ + { + "name": "request", + "comments": [ + "The refresh token access token exchange request." + ], + "type": "body", + "javaType": "RefreshTokenAccessTokenRequest" + } + ] +} diff --git a/src/main/api/exchangeUserCredentialsForAccessToken.json b/src/main/api/exchangeUserCredentialsForAccessToken.json index 57427d7..e629890 100644 --- a/src/main/api/exchangeUserCredentialsForAccessToken.json +++ b/src/main/api/exchangeUserCredentialsForAccessToken.json @@ -68,14 +68,6 @@ ], "type": "form", "javaType": "String" - }, - { - "name": "tenantId", - "comments": [ - "(Optional) The Id of the tenant to use for this request." - ], - "type": "form", - "javaType": "UUID" } ] } diff --git a/src/main/api/exchangeUserCredentialsForAccessTokenUsingRequest.json b/src/main/api/exchangeUserCredentialsForAccessTokenUsingRequest.json new file mode 100644 index 0000000..d5781b5 --- /dev/null +++ b/src/main/api/exchangeUserCredentialsForAccessTokenUsingRequest.json @@ -0,0 +1,22 @@ +{ + "uri": "/oauth2/token", + "comments": [ + "Exchange User Credentials for a Token.", + "If you will be using the Resource Owner Password Credential Grant, you will make a request to the Token endpoint to exchange the user’s email and password for an access token." + ], + "method": "post", + "methodName": "exchangeUserCredentialsForAccessTokenWithRequest", + "successResponse": "AccessToken", + "errorResponse": "OAuthError", + "anonymous": true, + "params": [ + { + "name": "request", + "comments": [ + "The user credentials access token exchange request." + ], + "type": "body", + "javaType": "UserCredentialsAccessTokenRequest" + } + ] +} diff --git a/src/main/api/introspectAccessToken.json b/src/main/api/introspectAccessToken.json index fea4ede..eca940d 100644 --- a/src/main/api/introspectAccessToken.json +++ b/src/main/api/introspectAccessToken.json @@ -24,14 +24,6 @@ ], "type": "form", "javaType": "String" - }, - { - "name": "tenantId", - "comments": [ - "(Optional) The Id of the tenant to use for this request." - ], - "type": "form", - "javaType": "UUID" } ] } diff --git a/src/main/api/introspectAccessTokenUsingRequest.json b/src/main/api/introspectAccessTokenUsingRequest.json new file mode 100644 index 0000000..31ab583 --- /dev/null +++ b/src/main/api/introspectAccessTokenUsingRequest.json @@ -0,0 +1,21 @@ +{ + "uri": "/oauth2/introspect", + "comments": [ + "Inspect an access token issued as the result of the User based grant such as the Authorization Code Grant, Implicit Grant, the User Credentials Grant or the Refresh Grant." + ], + "method": "post", + "methodName": "introspectAccessTokenWithRequest", + "successResponse": "IntrospectResponse", + "errorResponse": "OAuthError", + "anonymous": true, + "params": [ + { + "name": "request", + "comments": [ + "The access token introspection request." + ], + "type": "body", + "javaType": "AccessTokenIntrospectRequest" + } + ] +} diff --git a/src/main/api/introspectClientCredentialsAccessToken.json b/src/main/api/introspectClientCredentialsAccessToken.json index a303e76..7a538ca 100644 --- a/src/main/api/introspectClientCredentialsAccessToken.json +++ b/src/main/api/introspectClientCredentialsAccessToken.json @@ -16,14 +16,6 @@ ], "type": "form", "javaType": "String" - }, - { - "name": "tenantId", - "comments": [ - "(Optional) The Id of the tenant to use for this request." - ], - "type": "form", - "javaType": "UUID" } ] } diff --git a/src/main/api/introspectClientCredentialsAccessTokenUsingRequest.json b/src/main/api/introspectClientCredentialsAccessTokenUsingRequest.json new file mode 100644 index 0000000..0939440 --- /dev/null +++ b/src/main/api/introspectClientCredentialsAccessTokenUsingRequest.json @@ -0,0 +1,21 @@ +{ + "uri": "/oauth2/introspect", + "comments": [ + "Inspect an access token issued as the result of the Client Credentials Grant." + ], + "method": "post", + "methodName": "introspectClientCredentialsAccessTokenWithRequest", + "successResponse": "IntrospectResponse", + "errorResponse": "OAuthError", + "anonymous": true, + "params": [ + { + "name": "request", + "comments": [ + "The client credentials access token." + ], + "type": "body", + "javaType": "ClientCredentialsAccessTokenIntrospectRequest" + } + ] +} diff --git a/src/main/api/retrieveUserCode.json b/src/main/api/retrieveUserCode.json index 377d89e..7fdf7e8 100644 --- a/src/main/api/retrieveUserCode.json +++ b/src/main/api/retrieveUserCode.json @@ -37,15 +37,6 @@ "type": "form", "parameterName": "user_code", "javaType": "String" - }, - { - "name": "tenantId", - "comments": [ - "(Optional) The Id of the tenant to use for this request." - ], - "type": "urlParameter", - "parameterName": "tenantId", - "javaType": "UUID" } ] } diff --git a/src/main/api/retrieveUserCodeUsingAPIKey.json b/src/main/api/retrieveUserCodeUsingAPIKey.json index a336f1d..a55f6bb 100644 --- a/src/main/api/retrieveUserCodeUsingAPIKey.json +++ b/src/main/api/retrieveUserCodeUsingAPIKey.json @@ -21,15 +21,6 @@ "type": "form", "parameterName": "user_code", "javaType": "String" - }, - { - "name": "tenantId", - "comments": [ - "(Optional) The Id of the tenant to use for this request." - ], - "type": "urlParameter", - "parameterName": "tenantId", - "javaType": "UUID" } ] } diff --git a/src/main/api/retrieveUserCodeUsingAPIKeyUsingRequest.json b/src/main/api/retrieveUserCodeUsingAPIKeyUsingRequest.json new file mode 100644 index 0000000..0c5cb72 --- /dev/null +++ b/src/main/api/retrieveUserCodeUsingAPIKeyUsingRequest.json @@ -0,0 +1,25 @@ +{ + "uri": "/oauth2/device/user-code", + "comments": [ + "Retrieve a user_code that is part of an in-progress Device Authorization Grant.", + "", + "This API is useful if you want to build your own login workflow to complete a device grant.", + "", + "This request will require an API key." + ], + "method": "post", + "methodName": "retrieveUserCodeUsingAPIKeyWithRequest", + "successResponse": "Void", + "errorResponse": "Void", + "anonymous": false, + "params": [ + { + "name": "request", + "comments": [ + "The user code retrieval request including optional tenantId." + ], + "type": "body", + "javaType": "RetrieveUserCodeUsingAPIKeyRequest" + } + ] +} diff --git a/src/main/api/retrieveUserCodeUsingRequest.json b/src/main/api/retrieveUserCodeUsingRequest.json new file mode 100644 index 0000000..20d6dd5 --- /dev/null +++ b/src/main/api/retrieveUserCodeUsingRequest.json @@ -0,0 +1,23 @@ +{ + "uri": "/oauth2/device/user-code", + "comments": [ + "Retrieve a user_code that is part of an in-progress Device Authorization Grant.", + "", + "This API is useful if you want to build your own login workflow to complete a device grant." + ], + "method": "post", + "methodName": "retrieveUserCodeWithRequest", + "successResponse": "Void", + "errorResponse": "Void", + "anonymous": true, + "params": [ + { + "name": "request", + "comments": [ + "The user code retrieval request." + ], + "type": "body", + "javaType": "RetrieveUserCodeRequest" + } + ] +} diff --git a/src/main/api/validateDevice.json b/src/main/api/validateDevice.json index 3c25cde..f47c7a6 100644 --- a/src/main/api/validateDevice.json +++ b/src/main/api/validateDevice.json @@ -27,15 +27,6 @@ "type": "urlParameter", "parameterName": "client_id", "javaType": "String" - }, - { - "name": "tenantId", - "comments": [ - "(Optional) The Id of the tenant to use for this request." - ], - "type": "urlParameter", - "parameterName": "tenantId", - "javaType": "UUID" } ] } diff --git a/src/main/api/validateDeviceUsingRequest.json b/src/main/api/validateDeviceUsingRequest.json new file mode 100644 index 0000000..a984b52 --- /dev/null +++ b/src/main/api/validateDeviceUsingRequest.json @@ -0,0 +1,22 @@ +{ + "uri": "/oauth2/device/validate", + "comments": [ + "Validates the end-user provided user_code from the user-interaction of the Device Authorization Grant.", + "If you build your own activation form you should validate the user provided code prior to beginning the Authorization grant." + ], + "method": "post", + "methodName": "validateDeviceWithRequest", + "successResponse": "Void", + "errorResponse": "Void", + "anonymous": true, + "params": [ + { + "name": "request", + "comments": [ + "The device validation request." + ], + "type": "body", + "javaType": "ValidateDeviceRequest" + } + ] +} diff --git a/src/main/client/java.client.ftl b/src/main/client/java.client.ftl index f04382c..34ba99f 100644 --- a/src/main/client/java.client.ftl +++ b/src/main/client/java.client.ftl @@ -238,11 +238,22 @@ import io.fusionauth.domain.api.user.VerifyEmailResponse; import io.fusionauth.domain.api.user.VerifyRegistrationRequest; import io.fusionauth.domain.api.user.VerifyRegistrationResponse; import io.fusionauth.domain.oauth2.AccessToken; +import io.fusionauth.domain.oauth2.AccessTokenIntrospectRequest; +import io.fusionauth.domain.oauth2.ClientCredentialsAccessTokenIntrospectRequest; +import io.fusionauth.domain.oauth2.ClientCredentialsGrantRequest; +import io.fusionauth.domain.oauth2.DeviceApprovalRequest; import io.fusionauth.domain.oauth2.DeviceApprovalResponse; import io.fusionauth.domain.oauth2.IntrospectResponse; import io.fusionauth.domain.oauth2.JWKSResponse; +import io.fusionauth.domain.oauth2.OAuthCodeAccessTokenRequest; +import io.fusionauth.domain.oauth2.OAuthCodePKCEAccessTokenRequest; import io.fusionauth.domain.oauth2.OAuthError; +import io.fusionauth.domain.oauth2.RefreshTokenAccessTokenRequest; +import io.fusionauth.domain.oauth2.RetrieveUserCodeRequest; +import io.fusionauth.domain.oauth2.RetrieveUserCodeUsingAPIKeyRequest; +import io.fusionauth.domain.oauth2.UserCredentialsAccessTokenRequest; import io.fusionauth.domain.oauth2.UserinfoResponse; +import io.fusionauth.domain.oauth2.ValidateDeviceRequest; import io.fusionauth.domain.provider.IdentityProviderType; /** From 7640aac0d011286496f860e6ebf5273f7c69c569 Mon Sep 17 00:00:00 2001 From: Lyle Schemmerling Date: Tue, 23 Sep 2025 12:42:53 -0600 Subject: [PATCH 3/9] fix imports and user info --- src/main/api/retrieveUserInfoFromAccessToken.json | 9 --------- src/main/client/java.client.ftl | 2 ++ 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/src/main/api/retrieveUserInfoFromAccessToken.json b/src/main/api/retrieveUserInfoFromAccessToken.json index 305dced..7bccd07 100644 --- a/src/main/api/retrieveUserInfoFromAccessToken.json +++ b/src/main/api/retrieveUserInfoFromAccessToken.json @@ -17,15 +17,6 @@ ], "type": "notUsed", "javaType": "String" - }, - { - "name": "tenantId", - "comments": [ - "(Optional) The Id of the tenant to use for this request." - ], - "type": "urlParameter", - "parameterName": "tenantId", - "javaType": "UUID" } ] } diff --git a/src/main/client/java.client.ftl b/src/main/client/java.client.ftl index 34ba99f..aae63ec 100644 --- a/src/main/client/java.client.ftl +++ b/src/main/client/java.client.ftl @@ -243,6 +243,8 @@ import io.fusionauth.domain.oauth2.ClientCredentialsAccessTokenIntrospectRequest import io.fusionauth.domain.oauth2.ClientCredentialsGrantRequest; import io.fusionauth.domain.oauth2.DeviceApprovalRequest; import io.fusionauth.domain.oauth2.DeviceApprovalResponse; +import io.fusionauth.domain.oauth2.DeviceAuthorizationRequest; +import io.fusionauth.domain.oauth2.DeviceResponse; import io.fusionauth.domain.oauth2.IntrospectResponse; import io.fusionauth.domain.oauth2.JWKSResponse; import io.fusionauth.domain.oauth2.OAuthCodeAccessTokenRequest; From a28748d0fba9695d40b0c8ae6a2fd9fd2ec625a8 Mon Sep 17 00:00:00 2001 From: Lyle Schemmerling Date: Tue, 23 Sep 2025 13:07:58 -0600 Subject: [PATCH 4/9] remove incompatible go methods --- src/main/client/go.client.ftl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/client/go.client.ftl b/src/main/client/go.client.ftl index 1ce43cd..4761fbf 100644 --- a/src/main/client/go.client.ftl +++ b/src/main/client/go.client.ftl @@ -184,7 +184,7 @@ func (rc *restClient) WithUriSegment(segment string) *restClient { [#-- @formatter:off --] [#-- Ignoring these few following APIs due to currently being unable to convert the json response into the actual IdentityProvider type. Need a conversion utility. --] -[#assign ignoredAPIs = ["CreateIdentityProvider","IntrospectAccessToken","IntrospectClientCredentialsAccessToken","RetrieveIdentityProvider","RetrieveIdentityProviders","RetrieveUserInfoFromAccessToken","UpdateIdentityProvider"]/] +[#assign ignoredAPIs = ["CreateIdentityProvider","IntrospectAccessToken","IntrospectAccessTokenWithRequest","IntrospectClientCredentialsAccessToken","IntrospectClientCredentialsAccessTokenWithRequest","RetrieveIdentityProvider","RetrieveIdentityProviders","RetrieveUserInfoFromAccessToken","UpdateIdentityProvider"]/] [#list apis as api] [#if !(ignoredAPIs?seq_contains(api.methodName?cap_first))] // ${api.methodName?cap_first} From 414d0b1d1701ca95cba1b0769f3e47a24af2d246 Mon Sep 17 00:00:00 2001 From: Lyle Schemmerling Date: Wed, 17 Dec 2025 11:26:08 -0700 Subject: [PATCH 5/9] PR Feedback, additional validation on oauth routes affected by the tenant id checks, update the client libraries to pass in the tenant id in request objects to preserve backwards compat, additional testing, and some cleanup --- ...est.json => approveDeviceWithRequest.json} | 2 +- ...=> clientCredentialsGrantWithRequest.json} | 2 +- ...t.json => deviceAuthorizeWithRequest.json} | 4 +-- ...deForAccessTokenUsingPKCEWithRequest.json} | 2 +- ...geOAuthCodeForAccessTokenWithRequest.json} | 2 +- ...efreshTokenForAccessTokenWithRequest.json} | 2 +- ...CredentialsForAccessTokenWithRequest.json} | 2 +- ... => introspectAccessTokenWithRequest.json} | 2 +- ...entCredentialsAccessTokenWithRequest.json} | 2 +- ...trieveUserCodeUsingAPIKeyWithRequest.json} | 2 +- ....json => retrieveUserCodeWithRequest.json} | 2 +- ...st.json => validateDeviceWithRequest.json} | 2 +- src/main/client/go.client.ftl | 22 ++++++++++++++- src/main/client/java.client.ftl | 19 ++++++++++++- src/main/client/netcore.client.ftl | 27 +++++++++++++------ src/main/client/php.client.ftl | 18 ++++++++++++- src/main/client/python.client.ftl | 16 ++++++++++- src/main/client/ruby.client.ftl | 24 ++++++++++++++--- src/main/client/typescript.client.ftl | 18 ++++++++++++- 19 files changed, 140 insertions(+), 30 deletions(-) rename src/main/api/{approveDeviceUsingRequest.json => approveDeviceWithRequest.json} (94%) rename src/main/api/{clientCredentialsGrantUsingRequest.json => clientCredentialsGrantWithRequest.json} (95%) rename src/main/api/{deviceAuthorizeUsingRequest.json => deviceAuthorizeWithRequest.json} (94%) rename src/main/api/{exchangeOAuthCodeForAccessTokenUsingPKCEUsingRequest.json => exchangeOAuthCodeForAccessTokenUsingPKCEWithRequest.json} (96%) rename src/main/api/{exchangeOAuthCodeForAccessTokenUsingRequest.json => exchangeOAuthCodeForAccessTokenWithRequest.json} (95%) rename src/main/api/{exchangeRefreshTokenForAccessTokenUsingRequest.json => exchangeRefreshTokenForAccessTokenWithRequest.json} (96%) rename src/main/api/{exchangeUserCredentialsForAccessTokenUsingRequest.json => exchangeUserCredentialsForAccessTokenWithRequest.json} (96%) rename src/main/api/{introspectAccessTokenUsingRequest.json => introspectAccessTokenWithRequest.json} (95%) rename src/main/api/{introspectClientCredentialsAccessTokenUsingRequest.json => introspectClientCredentialsAccessTokenWithRequest.json} (95%) rename src/main/api/{retrieveUserCodeUsingAPIKeyUsingRequest.json => retrieveUserCodeUsingAPIKeyWithRequest.json} (96%) rename src/main/api/{retrieveUserCodeUsingRequest.json => retrieveUserCodeWithRequest.json} (95%) rename src/main/api/{validateDeviceUsingRequest.json => validateDeviceWithRequest.json} (95%) diff --git a/src/main/api/approveDeviceUsingRequest.json b/src/main/api/approveDeviceWithRequest.json similarity index 94% rename from src/main/api/approveDeviceUsingRequest.json rename to src/main/api/approveDeviceWithRequest.json index 14e47ff..223499d 100644 --- a/src/main/api/approveDeviceUsingRequest.json +++ b/src/main/api/approveDeviceWithRequest.json @@ -13,7 +13,7 @@ "comments": [ "The request object containing the device approval information and optional tenantId." ], - "type": "body", + "type": "formBody", "javaType": "DeviceApprovalRequest" } ] diff --git a/src/main/api/clientCredentialsGrantUsingRequest.json b/src/main/api/clientCredentialsGrantWithRequest.json similarity index 95% rename from src/main/api/clientCredentialsGrantUsingRequest.json rename to src/main/api/clientCredentialsGrantWithRequest.json index 66cda12..c7060f9 100644 --- a/src/main/api/clientCredentialsGrantUsingRequest.json +++ b/src/main/api/clientCredentialsGrantWithRequest.json @@ -14,7 +14,7 @@ "comments": [ "The client credentials grant request containing client authentication, scope and optional tenantId." ], - "type": "body", + "type": "formBody", "javaType": "ClientCredentialsGrantRequest" } ] diff --git a/src/main/api/deviceAuthorizeUsingRequest.json b/src/main/api/deviceAuthorizeWithRequest.json similarity index 94% rename from src/main/api/deviceAuthorizeUsingRequest.json rename to src/main/api/deviceAuthorizeWithRequest.json index ce22219..0b46d96 100644 --- a/src/main/api/deviceAuthorizeUsingRequest.json +++ b/src/main/api/deviceAuthorizeWithRequest.json @@ -14,8 +14,8 @@ "comments": [ "The device authorization request containing client authentication, scope, and optional device metadata." ], - "type": "body", + "type": "formBody", "javaType": "DeviceAuthorizationRequest" } ] -} \ No newline at end of file +} diff --git a/src/main/api/exchangeOAuthCodeForAccessTokenUsingPKCEUsingRequest.json b/src/main/api/exchangeOAuthCodeForAccessTokenUsingPKCEWithRequest.json similarity index 96% rename from src/main/api/exchangeOAuthCodeForAccessTokenUsingPKCEUsingRequest.json rename to src/main/api/exchangeOAuthCodeForAccessTokenUsingPKCEWithRequest.json index 2d0bfe3..84a2f6b 100644 --- a/src/main/api/exchangeOAuthCodeForAccessTokenUsingPKCEUsingRequest.json +++ b/src/main/api/exchangeOAuthCodeForAccessTokenUsingPKCEWithRequest.json @@ -15,7 +15,7 @@ "comments": [ "The PKCE OAuth code access token exchange request." ], - "type": "body", + "type": "formBody", "javaType": "OAuthCodePKCEAccessTokenRequest" } ] diff --git a/src/main/api/exchangeOAuthCodeForAccessTokenUsingRequest.json b/src/main/api/exchangeOAuthCodeForAccessTokenWithRequest.json similarity index 95% rename from src/main/api/exchangeOAuthCodeForAccessTokenUsingRequest.json rename to src/main/api/exchangeOAuthCodeForAccessTokenWithRequest.json index 50f1336..a661049 100644 --- a/src/main/api/exchangeOAuthCodeForAccessTokenUsingRequest.json +++ b/src/main/api/exchangeOAuthCodeForAccessTokenWithRequest.json @@ -15,7 +15,7 @@ "comments": [ "The OAuth code access token exchange request." ], - "type": "body", + "type": "formBody", "javaType": "OAuthCodeAccessTokenRequest" } ] diff --git a/src/main/api/exchangeRefreshTokenForAccessTokenUsingRequest.json b/src/main/api/exchangeRefreshTokenForAccessTokenWithRequest.json similarity index 96% rename from src/main/api/exchangeRefreshTokenForAccessTokenUsingRequest.json rename to src/main/api/exchangeRefreshTokenForAccessTokenWithRequest.json index 840373b..a4783da 100644 --- a/src/main/api/exchangeRefreshTokenForAccessTokenUsingRequest.json +++ b/src/main/api/exchangeRefreshTokenForAccessTokenWithRequest.json @@ -15,7 +15,7 @@ "comments": [ "The refresh token access token exchange request." ], - "type": "body", + "type": "formBody", "javaType": "RefreshTokenAccessTokenRequest" } ] diff --git a/src/main/api/exchangeUserCredentialsForAccessTokenUsingRequest.json b/src/main/api/exchangeUserCredentialsForAccessTokenWithRequest.json similarity index 96% rename from src/main/api/exchangeUserCredentialsForAccessTokenUsingRequest.json rename to src/main/api/exchangeUserCredentialsForAccessTokenWithRequest.json index d5781b5..9443eca 100644 --- a/src/main/api/exchangeUserCredentialsForAccessTokenUsingRequest.json +++ b/src/main/api/exchangeUserCredentialsForAccessTokenWithRequest.json @@ -15,7 +15,7 @@ "comments": [ "The user credentials access token exchange request." ], - "type": "body", + "type": "formBody", "javaType": "UserCredentialsAccessTokenRequest" } ] diff --git a/src/main/api/introspectAccessTokenUsingRequest.json b/src/main/api/introspectAccessTokenWithRequest.json similarity index 95% rename from src/main/api/introspectAccessTokenUsingRequest.json rename to src/main/api/introspectAccessTokenWithRequest.json index 31ab583..f079e50 100644 --- a/src/main/api/introspectAccessTokenUsingRequest.json +++ b/src/main/api/introspectAccessTokenWithRequest.json @@ -14,7 +14,7 @@ "comments": [ "The access token introspection request." ], - "type": "body", + "type": "formBody", "javaType": "AccessTokenIntrospectRequest" } ] diff --git a/src/main/api/introspectClientCredentialsAccessTokenUsingRequest.json b/src/main/api/introspectClientCredentialsAccessTokenWithRequest.json similarity index 95% rename from src/main/api/introspectClientCredentialsAccessTokenUsingRequest.json rename to src/main/api/introspectClientCredentialsAccessTokenWithRequest.json index 0939440..a8f9cde 100644 --- a/src/main/api/introspectClientCredentialsAccessTokenUsingRequest.json +++ b/src/main/api/introspectClientCredentialsAccessTokenWithRequest.json @@ -14,7 +14,7 @@ "comments": [ "The client credentials access token." ], - "type": "body", + "type": "formBody", "javaType": "ClientCredentialsAccessTokenIntrospectRequest" } ] diff --git a/src/main/api/retrieveUserCodeUsingAPIKeyUsingRequest.json b/src/main/api/retrieveUserCodeUsingAPIKeyWithRequest.json similarity index 96% rename from src/main/api/retrieveUserCodeUsingAPIKeyUsingRequest.json rename to src/main/api/retrieveUserCodeUsingAPIKeyWithRequest.json index 0c5cb72..fdc9014 100644 --- a/src/main/api/retrieveUserCodeUsingAPIKeyUsingRequest.json +++ b/src/main/api/retrieveUserCodeUsingAPIKeyWithRequest.json @@ -18,7 +18,7 @@ "comments": [ "The user code retrieval request including optional tenantId." ], - "type": "body", + "type": "formBody", "javaType": "RetrieveUserCodeUsingAPIKeyRequest" } ] diff --git a/src/main/api/retrieveUserCodeUsingRequest.json b/src/main/api/retrieveUserCodeWithRequest.json similarity index 95% rename from src/main/api/retrieveUserCodeUsingRequest.json rename to src/main/api/retrieveUserCodeWithRequest.json index 20d6dd5..2ad3334 100644 --- a/src/main/api/retrieveUserCodeUsingRequest.json +++ b/src/main/api/retrieveUserCodeWithRequest.json @@ -16,7 +16,7 @@ "comments": [ "The user code retrieval request." ], - "type": "body", + "type": "formBody", "javaType": "RetrieveUserCodeRequest" } ] diff --git a/src/main/api/validateDeviceUsingRequest.json b/src/main/api/validateDeviceWithRequest.json similarity index 95% rename from src/main/api/validateDeviceUsingRequest.json rename to src/main/api/validateDeviceWithRequest.json index a984b52..3dbc3cd 100644 --- a/src/main/api/validateDeviceUsingRequest.json +++ b/src/main/api/validateDeviceWithRequest.json @@ -15,7 +15,7 @@ "comments": [ "The device validation request." ], - "type": "body", + "type": "formBody", "javaType": "ValidateDeviceRequest" } ] diff --git a/src/main/client/go.client.ftl b/src/main/client/go.client.ftl index 4761fbf..5baf950 100644 --- a/src/main/client/go.client.ftl +++ b/src/main/client/go.client.ftl @@ -225,13 +225,33 @@ func (c *FusionAuthClient) ${api.methodName?cap_first}WithContext(ctx context.Co [/#if] [#assign formPost = false/] [#list api.params![] as param] - [#if param.type == "form"][#assign formPost = true/][/#if] + [#if param.type == "form" || param.type == "formBody"][#assign formPost = true/][/#if] [/#list] [#if formPost] formBody := url.Values{} [#list api.params![] as param] [#if param.type == "form"] formBody.Set("${param.name}", ${(param.constant?? && param.constant)?then("\""+param.value+"\"", global.convertValue(param.name, "go"))}) + [#elseif param.type == "formBody"] + [#-- Lookup the domain object by javaType --] + [#list domain as d] + [#if d.type == param.javaType] + [#-- Iterate through all fields in the domain object --] + [#list d.fields as fieldName, field] + [#if field.type == "UUID"] + if request.${global.convertValue(fieldName, "go")} != nil { + formBody.Set("${fieldName}", request.${global.convertValue(fieldName, "go")}.String()) + } + [#elseif field.type == "String"] + formBody.Set("${fieldName}", request.${global.convertValue(fieldName, "go")}) + [#else] + if request.${global.convertValue(fieldName, "go")} != nil { + formBody.Set("${fieldName}", fmt.Sprintf("%v", request.${global.convertValue(fieldName, "go")})) + } + [/#if] + [/#list] + [/#if] + [/#list] [/#if] [/#list] [/#if] diff --git a/src/main/client/java.client.ftl b/src/main/client/java.client.ftl index aae63ec..25b33bb 100644 --- a/src/main/client/java.client.ftl +++ b/src/main/client/java.client.ftl @@ -371,7 +371,7 @@ public class FusionAuthClient { public ClientResponse<${api.successResponse}, ${api.errorResponse}> ${api.methodName}(${global.methodParameters(api, "java")}) { [#assign formPost = false/] [#list api.params![] as param] - [#if param.type == "form"][#assign formPost = true/][/#if] + [#if param.type == "form" || param.type == "formBody"][#assign formPost = true/][/#if] [/#list] [#if formPost] Map> parameters = new HashMap<>(); @@ -387,6 +387,23 @@ public class FusionAuthClient { [/#if] parameters.put("${param.name}", Arrays.asList(${pval})); [/#if] + [#if param.type == "formBody"] + [#-- Lookup the domain object by javaType --] + [#list domain as d] + [#if d.type == param.javaType] + [#-- Iterate through all fields in the domain object --] + [#list d.fields as fieldName, field] + [#if field.type == "String"] + parameters.put("${fieldName}", Arrays.asList(request.${fieldName})); + [#else] + if (request.${fieldName} != null) { + parameters.put("${fieldName}", Arrays.asList(request.${fieldName}.toString())); + } + [/#if] + [/#list] + [/#if] + [/#list] + [/#if] [/#list] [/#if] return start[#if api.anonymous??]Anonymous[/#if](${api.successResponse}.${(api.successResponse == 'Void')?then('TYPE', 'class')}, ${api.errorResponse}.${(api.errorResponse == 'Void')?then('TYPE', 'class')}) diff --git a/src/main/client/netcore.client.ftl b/src/main/client/netcore.client.ftl index e60ea0d..a444701 100644 --- a/src/main/client/netcore.client.ftl +++ b/src/main/client/netcore.client.ftl @@ -99,16 +99,27 @@ namespace io.fusionauth { public Task> ${api.methodName?cap_first}Async(${global.methodParameters(api, "csharp")}) { [#assign formPost = false/] [#list api.params![] as param] - [#if param.type == "form"][#assign formPost = true/][/#if] + [#if param.type == "form" || param.type == "formBody"][#assign formPost = true/][/#if] [/#list] [#if formPost] - var body = new Dictionary { - [#list api.params![] as param] - [#if param.type == "form"] - { "${param.name}", ${(param.constant?? && param.constant)?then("\""+param.value+"\"", param.name)} }, - [/#if] - [/#list] - }; + var body = new Dictionary(); + [#list api.params![] as param] + [#if param.type == "form"] + body.Add("${param.name}", ${(param.constant?? && param.constant)?then("\""+param.value+"\"", param.name)}); + [#elseif param.type == "formBody"] + [#-- Lookup the domain object by javaType --] + [#list domain as d] + [#if d.type == param.javaType] + [#-- Iterate through all fields in the domain object --] + [#list d.fields as fieldName, field] + if (request.${fieldName} != null) { + body.Add("${fieldName}", request.${fieldName}.ToString()); + } + [/#list] + [/#if] + [/#list] + [/#if] + [/#list] [/#if] return build[#if api.anonymous??]Anonymous[/#if]Client() .withUri("${api.uri}") diff --git a/src/main/client/php.client.ftl b/src/main/client/php.client.ftl index 65293e5..aaf709f 100644 --- a/src/main/client/php.client.ftl +++ b/src/main/client/php.client.ftl @@ -100,14 +100,30 @@ class FusionAuthClient public function ${api.methodName}(${global.methodParameters(api, "php")}) { [#assign formPost = false/] + [#assign hasFormParams = false/] [#list api.params![] as param] - [#if param.type == "form"][#assign formPost = true/][/#if] + [#if param.type == "form" || param.type == "formBody"][#assign formPost = true/][/#if] + [#if param.type == "form"][#assign hasFormParams = true/][/#if] [/#list] [#if formPost] $post_data = array( [#list api.params![] as param] [#if param.type == "form"] '${param.name}' => ${(param.constant?? && param.constant)?then("'"+param.value+"'", "$"+param.name)}[#if param?has_next],[/#if] + [#elseif param.type == "formBody"] + [#-- Lookup the domain object by javaType --] + [#list domain as d] + [#if d.type == param.javaType] + [#-- Iterate through all fields in the domain object --] + [#list d.fields as fieldName, field] + [#if field.type == "String"] + [#if fieldName?is_first && !hasFormParams][#else],[/#if]'${fieldName}' => $request->${fieldName} + [#else] + [#if fieldName?is_first && !hasFormParams][#else],[/#if]'${fieldName}' => ($request->${fieldName} !== null ? (string)$request->${fieldName} : null) + [/#if] + [/#list] + [/#if] + [/#list] [/#if] [/#list] ); diff --git a/src/main/client/python.client.ftl b/src/main/client/python.client.ftl index 82b23c5..23c593a 100644 --- a/src/main/client/python.client.ftl +++ b/src/main/client/python.client.ftl @@ -54,13 +54,27 @@ class FusionAuthClient: """ [#assign formPost = false/] [#list api.params![] as param] - [#if param.type == "form"][#assign formPost = true/][/#if] + [#if param.type == "form" || param.type == "formBody"][#assign formPost = true/][/#if] [/#list] [#if formPost] body = { [#list api.params![] as param] [#if param.type == "form"] "${param.name}": ${(param.constant?? && param.constant)?then("\""+param.value+"\"", param.name)}, + [#elseif param.type == "formBody"] + [#-- Lookup the domain object by javaType --] + [#list domain as d] + [#if d.type == param.javaType] + [#-- Iterate through all fields in the domain object --] + [#list d.fields as fieldName, field] + [#if field.type == "String"] + "${fieldName}": request.${fieldName}, + [#else] + "${fieldName}": str(request.${fieldName}) if request.${fieldName} is not None else None, + [/#if] + [/#list] + [/#if] + [/#list] [/#if] [/#list] } diff --git a/src/main/client/ruby.client.ftl b/src/main/client/ruby.client.ftl index 626bed3..2e649f4 100644 --- a/src/main/client/ruby.client.ftl +++ b/src/main/client/ruby.client.ftl @@ -59,14 +59,30 @@ module FusionAuth [/#if] def ${camel_to_underscores(api.methodName)}[#if (api.params![])?filter(p -> !p.constant??)?has_content](${global.methodParameters(api, "ruby")})[/#if] [#assign formPost = false/] + [#assign hasFormParams = false/] [#list api.params![] as param] - [#if param.type == "form"][#assign formPost = true/][/#if] + [#if param.type == "form" || param.type == "formBody"][#assign formPost = true/][/#if] + [#if param.type == "form"][#assign hasFormParams = true/][/#if] [/#list] [#if formPost] - body = { + form_parameters = { [#list api.params![] as param] [#if param.type == "form"] - "${param.name}" => ${(param.constant?? && param.constant)?then("\""+param.value+"\"", param.name)}[#if param?has_next],[/#if] + "${param.name}" => ${(param.constant?? && param.constant)?then("'"+param.value+"'", camel_to_underscores(param.name))}, + [#elseif param.type == "formBody"] + [#-- Lookup the domain object by javaType --] + [#list domain as d] + [#if d.type == param.javaType] + [#-- Iterate through all fields in the domain object --] + [#list d.fields as fieldName, field] + [#if field.type == "String"] + "${fieldName}" => request.${fieldName}, + [#else] + "${fieldName}" => (request.${fieldName}.to_s unless request.${fieldName}.nil?), + [/#if] + [/#list] + [/#if] + [/#list] [/#if] [/#list] } @@ -85,7 +101,7 @@ module FusionAuth [/#if] [/#list] [#if formPost] - .body_handler(FusionAuth::FormDataBodyHandler.new(body)) + .body_handler(FusionAuth::FormDataBodyHandler.new(form_parameters)) [/#if] .${api.method} .go diff --git a/src/main/client/typescript.client.ftl b/src/main/client/typescript.client.ftl index 04896b9..b888c7e 100644 --- a/src/main/client/typescript.client.ftl +++ b/src/main/client/typescript.client.ftl @@ -77,7 +77,7 @@ export class FusionAuthClient { ${api.methodName}(${parameters}): Promise> { [#assign formPost = false/] [#list api.params![] as param] - [#if param.type == "form"][#assign formPost = true/][/#if] + [#if param.type == "form" || param.type == "formBody"][#assign formPost = true/][/#if] [/#list] [#if formPost] let body = new URLSearchParams(); @@ -85,6 +85,22 @@ export class FusionAuthClient { [#list api.params![] as param] [#if param.type == "form"] body.append('${param.name}', ${(param.constant?? && param.constant)?then("'"+param.value+"'", param.name)}); + [#elseif param.type == "formBody"] + [#-- Lookup the domain object by javaType --] + [#list domain as d] + [#if d.type == param.javaType] + [#-- Iterate through all fields in the domain object --] + [#list d.fields as fieldName, field] + if (request.${fieldName} !== null && request.${fieldName} !== undefined) { + [#if field.type == "String"] + body.append('${fieldName}', request.${fieldName}); + [#else] + body.append('${fieldName}', request.${fieldName}.toString()); + [/#if] + } + [/#list] + [/#if] + [/#list] [/#if] [/#list] [/#if] From b72b585bd97db510e92d868faa3f49ca9a6ecfba Mon Sep 17 00:00:00 2001 From: Lyle Schemmerling Date: Wed, 17 Dec 2025 12:32:52 -0700 Subject: [PATCH 6/9] fix the casing issue in the go client --- src/main/client/go.client.ftl | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/main/client/go.client.ftl b/src/main/client/go.client.ftl index 5baf950..bb33adc 100644 --- a/src/main/client/go.client.ftl +++ b/src/main/client/go.client.ftl @@ -238,15 +238,11 @@ func (c *FusionAuthClient) ${api.methodName?cap_first}WithContext(ctx context.Co [#if d.type == param.javaType] [#-- Iterate through all fields in the domain object --] [#list d.fields as fieldName, field] - [#if field.type == "UUID"] - if request.${global.convertValue(fieldName, "go")} != nil { - formBody.Set("${fieldName}", request.${global.convertValue(fieldName, "go")}.String()) - } - [#elseif field.type == "String"] - formBody.Set("${fieldName}", request.${global.convertValue(fieldName, "go")}) + [#if field.type == "UUID" || field.type == "String"] + formBody.Set("${fieldName}", request.${global.toCamelCase(fieldName)?cap_first}) [#else] - if request.${global.convertValue(fieldName, "go")} != nil { - formBody.Set("${fieldName}", fmt.Sprintf("%v", request.${global.convertValue(fieldName, "go")})) + if request.${global.toCamelCase(fieldName)?cap_first} != nil { + formBody.Set("${fieldName}", fmt.Sprintf("%v", request.${global.toCamelCase(fieldName)?cap_first})) } [/#if] [/#list] From 4bd0ae96a06ba4e1d216f803dc2d6e47789a2c53 Mon Sep 17 00:00:00 2001 From: Lyle Schemmerling Date: Wed, 17 Dec 2025 13:24:31 -0700 Subject: [PATCH 7/9] commit new domain files --- ...n.oauth2.AccessTokenIntrospectRequest.json | 16 ++++++++++ ...edentialsAccessTokenIntrospectRequest.json | 13 ++++++++ ....oauth2.ClientCredentialsGrantRequest.json | 22 +++++++++++++ ...h.domain.oauth2.DeviceApprovalRequest.json | 22 +++++++++++++ ...ain.oauth2.DeviceAuthorizationRequest.json | 19 ++++++++++++ ...in.oauth2.OAuthCodeAccessTokenRequest.json | 25 +++++++++++++++ ...auth2.OAuthCodePKCEAccessTokenRequest.json | 28 +++++++++++++++++ ...oauth2.RefreshTokenAccessTokenRequest.json | 28 +++++++++++++++++ ...domain.oauth2.RetrieveUserCodeRequest.json | 19 ++++++++++++ ...h2.RetrieveUserCodeUsingAPIKeyRequest.json | 13 ++++++++ ...th2.UserCredentialsAccessTokenRequest.json | 31 +++++++++++++++++++ ...h.domain.oauth2.ValidateDeviceRequest.json | 16 ++++++++++ 12 files changed, 252 insertions(+) create mode 100644 src/main/domain/io.fusionauth.domain.oauth2.AccessTokenIntrospectRequest.json create mode 100644 src/main/domain/io.fusionauth.domain.oauth2.ClientCredentialsAccessTokenIntrospectRequest.json create mode 100644 src/main/domain/io.fusionauth.domain.oauth2.ClientCredentialsGrantRequest.json create mode 100644 src/main/domain/io.fusionauth.domain.oauth2.DeviceApprovalRequest.json create mode 100644 src/main/domain/io.fusionauth.domain.oauth2.DeviceAuthorizationRequest.json create mode 100644 src/main/domain/io.fusionauth.domain.oauth2.OAuthCodeAccessTokenRequest.json create mode 100644 src/main/domain/io.fusionauth.domain.oauth2.OAuthCodePKCEAccessTokenRequest.json create mode 100644 src/main/domain/io.fusionauth.domain.oauth2.RefreshTokenAccessTokenRequest.json create mode 100644 src/main/domain/io.fusionauth.domain.oauth2.RetrieveUserCodeRequest.json create mode 100644 src/main/domain/io.fusionauth.domain.oauth2.RetrieveUserCodeUsingAPIKeyRequest.json create mode 100644 src/main/domain/io.fusionauth.domain.oauth2.UserCredentialsAccessTokenRequest.json create mode 100644 src/main/domain/io.fusionauth.domain.oauth2.ValidateDeviceRequest.json diff --git a/src/main/domain/io.fusionauth.domain.oauth2.AccessTokenIntrospectRequest.json b/src/main/domain/io.fusionauth.domain.oauth2.AccessTokenIntrospectRequest.json new file mode 100644 index 0000000..e40fa15 --- /dev/null +++ b/src/main/domain/io.fusionauth.domain.oauth2.AccessTokenIntrospectRequest.json @@ -0,0 +1,16 @@ +{ + "packageName" : "io.fusionauth.domain.oauth2", + "type" : "AccessTokenIntrospectRequest", + "description" : "/**\n * The request object for introspecting an access token.\n *\n * @author Lyle Schemmerling\n */\n", + "fields" : { + "client_id" : { + "type" : "String" + }, + "tenantId" : { + "type" : "String" + }, + "token" : { + "type" : "String" + } + } +} \ No newline at end of file diff --git a/src/main/domain/io.fusionauth.domain.oauth2.ClientCredentialsAccessTokenIntrospectRequest.json b/src/main/domain/io.fusionauth.domain.oauth2.ClientCredentialsAccessTokenIntrospectRequest.json new file mode 100644 index 0000000..a998fcf --- /dev/null +++ b/src/main/domain/io.fusionauth.domain.oauth2.ClientCredentialsAccessTokenIntrospectRequest.json @@ -0,0 +1,13 @@ +{ + "packageName" : "io.fusionauth.domain.oauth2", + "type" : "ClientCredentialsAccessTokenIntrospectRequest", + "description" : "/**\n * Contains the parameters used to introspect an access token that was obtained via the client credentials grant.\n *\n * @author Lyle Schemmerling\n */\n", + "fields" : { + "tenantId" : { + "type" : "String" + }, + "token" : { + "type" : "String" + } + } +} \ No newline at end of file diff --git a/src/main/domain/io.fusionauth.domain.oauth2.ClientCredentialsGrantRequest.json b/src/main/domain/io.fusionauth.domain.oauth2.ClientCredentialsGrantRequest.json new file mode 100644 index 0000000..25e1d72 --- /dev/null +++ b/src/main/domain/io.fusionauth.domain.oauth2.ClientCredentialsGrantRequest.json @@ -0,0 +1,22 @@ +{ + "packageName" : "io.fusionauth.domain.oauth2", + "type" : "ClientCredentialsGrantRequest", + "description" : "/**\n * The request object to make a Client Credentials grant request to obtain an access token.\n *\n * @author Lyle Schemmerling\n */\n", + "fields" : { + "client_id" : { + "type" : "String" + }, + "client_secret" : { + "type" : "String" + }, + "grant_type" : { + "type" : "String" + }, + "scope" : { + "type" : "String" + }, + "tenantId" : { + "type" : "String" + } + } +} \ No newline at end of file diff --git a/src/main/domain/io.fusionauth.domain.oauth2.DeviceApprovalRequest.json b/src/main/domain/io.fusionauth.domain.oauth2.DeviceApprovalRequest.json new file mode 100644 index 0000000..aafbebe --- /dev/null +++ b/src/main/domain/io.fusionauth.domain.oauth2.DeviceApprovalRequest.json @@ -0,0 +1,22 @@ +{ + "packageName" : "io.fusionauth.domain.oauth2", + "type" : "DeviceApprovalRequest", + "description" : "/**\n * The request object to approve a device grant.\n *\n * @author Lyle Schemmerling\n */\n", + "fields" : { + "client_id" : { + "type" : "String" + }, + "client_secret" : { + "type" : "String" + }, + "tenantId" : { + "type" : "UUID" + }, + "token" : { + "type" : "String" + }, + "user_code" : { + "type" : "String" + } + } +} \ No newline at end of file diff --git a/src/main/domain/io.fusionauth.domain.oauth2.DeviceAuthorizationRequest.json b/src/main/domain/io.fusionauth.domain.oauth2.DeviceAuthorizationRequest.json new file mode 100644 index 0000000..c2f04be --- /dev/null +++ b/src/main/domain/io.fusionauth.domain.oauth2.DeviceAuthorizationRequest.json @@ -0,0 +1,19 @@ +{ + "packageName" : "io.fusionauth.domain.oauth2", + "type" : "DeviceAuthorizationRequest", + "description" : "/**\n * @author Lyle Schemmerling\n */\n", + "fields" : { + "client_id" : { + "type" : "String" + }, + "client_secret" : { + "type" : "String" + }, + "scope" : { + "type" : "String" + }, + "tenantId" : { + "type" : "UUID" + } + } +} \ No newline at end of file diff --git a/src/main/domain/io.fusionauth.domain.oauth2.OAuthCodeAccessTokenRequest.json b/src/main/domain/io.fusionauth.domain.oauth2.OAuthCodeAccessTokenRequest.json new file mode 100644 index 0000000..1a13bd5 --- /dev/null +++ b/src/main/domain/io.fusionauth.domain.oauth2.OAuthCodeAccessTokenRequest.json @@ -0,0 +1,25 @@ +{ + "packageName" : "io.fusionauth.domain.oauth2", + "type" : "OAuthCodeAccessTokenRequest", + "description" : "/**\n * The request object for exchanging an OAuth authorization code for an access token.\n *\n * @author Lyle Schemmerling\n */\n", + "fields" : { + "client_id" : { + "type" : "String" + }, + "client_secret" : { + "type" : "String" + }, + "code" : { + "type" : "String" + }, + "grant_type" : { + "type" : "String" + }, + "redirect_uri" : { + "type" : "String" + }, + "tenantId" : { + "type" : "String" + } + } +} \ No newline at end of file diff --git a/src/main/domain/io.fusionauth.domain.oauth2.OAuthCodePKCEAccessTokenRequest.json b/src/main/domain/io.fusionauth.domain.oauth2.OAuthCodePKCEAccessTokenRequest.json new file mode 100644 index 0000000..60fdf94 --- /dev/null +++ b/src/main/domain/io.fusionauth.domain.oauth2.OAuthCodePKCEAccessTokenRequest.json @@ -0,0 +1,28 @@ +{ + "packageName" : "io.fusionauth.domain.oauth2", + "type" : "OAuthCodePKCEAccessTokenRequest", + "description" : "/**\n * The request object to make a request to the Token endpoint to exchange the authorization code returned from the Authorize endpoint and a\n * code_verifier for an access token.\n *\n * @author Lyle Schemmerling\n */\n", + "fields" : { + "client_id" : { + "type" : "String" + }, + "client_secret" : { + "type" : "String" + }, + "code" : { + "type" : "String" + }, + "code_verifier" : { + "type" : "String" + }, + "grant_type" : { + "type" : "String" + }, + "redirect_uri" : { + "type" : "String" + }, + "tenantId" : { + "type" : "UUID" + } + } +} \ No newline at end of file diff --git a/src/main/domain/io.fusionauth.domain.oauth2.RefreshTokenAccessTokenRequest.json b/src/main/domain/io.fusionauth.domain.oauth2.RefreshTokenAccessTokenRequest.json new file mode 100644 index 0000000..19d8fba --- /dev/null +++ b/src/main/domain/io.fusionauth.domain.oauth2.RefreshTokenAccessTokenRequest.json @@ -0,0 +1,28 @@ +{ + "packageName" : "io.fusionauth.domain.oauth2", + "type" : "RefreshTokenAccessTokenRequest", + "description" : "/**\n * The request object to exchange a Refresh Token for an Access Token.\n *\n * @author Lyle Schemmerling\n */\n", + "fields" : { + "client_id" : { + "type" : "String" + }, + "client_secret" : { + "type" : "String" + }, + "grant_type" : { + "type" : "String" + }, + "refresh_token" : { + "type" : "String" + }, + "scope" : { + "type" : "String" + }, + "tenantId" : { + "type" : "UUID" + }, + "user_code" : { + "type" : "String" + } + } +} \ No newline at end of file diff --git a/src/main/domain/io.fusionauth.domain.oauth2.RetrieveUserCodeRequest.json b/src/main/domain/io.fusionauth.domain.oauth2.RetrieveUserCodeRequest.json new file mode 100644 index 0000000..1665353 --- /dev/null +++ b/src/main/domain/io.fusionauth.domain.oauth2.RetrieveUserCodeRequest.json @@ -0,0 +1,19 @@ +{ + "packageName" : "io.fusionauth.domain.oauth2", + "type" : "RetrieveUserCodeRequest", + "description" : "/**\n * The request object for retrieving a user code that is part of an in-progress Device Authorization Grant.\n *\n * @author Lyle Schemmerling\n */\n", + "fields" : { + "client_id" : { + "type" : "String" + }, + "client_secret" : { + "type" : "String" + }, + "tenantId" : { + "type" : "UUID" + }, + "user_code" : { + "type" : "String" + } + } +} \ No newline at end of file diff --git a/src/main/domain/io.fusionauth.domain.oauth2.RetrieveUserCodeUsingAPIKeyRequest.json b/src/main/domain/io.fusionauth.domain.oauth2.RetrieveUserCodeUsingAPIKeyRequest.json new file mode 100644 index 0000000..e2b12ba --- /dev/null +++ b/src/main/domain/io.fusionauth.domain.oauth2.RetrieveUserCodeUsingAPIKeyRequest.json @@ -0,0 +1,13 @@ +{ + "packageName" : "io.fusionauth.domain.oauth2", + "type" : "RetrieveUserCodeUsingAPIKeyRequest", + "description" : "/**\n * The request object for retrieving a user code that is part of an in-progress Device Authorization Grant using an API key\n *\n * @author Lyle Schemmerling\n */\n", + "fields" : { + "tenantId" : { + "type" : "UUID" + }, + "user_code" : { + "type" : "String" + } + } +} \ No newline at end of file diff --git a/src/main/domain/io.fusionauth.domain.oauth2.UserCredentialsAccessTokenRequest.json b/src/main/domain/io.fusionauth.domain.oauth2.UserCredentialsAccessTokenRequest.json new file mode 100644 index 0000000..12a4527 --- /dev/null +++ b/src/main/domain/io.fusionauth.domain.oauth2.UserCredentialsAccessTokenRequest.json @@ -0,0 +1,31 @@ +{ + "packageName" : "io.fusionauth.domain.oauth2", + "type" : "UserCredentialsAccessTokenRequest", + "description" : "/**\n * The request object for exchanging user credentials (username and password) for an access token.\n *\n * @author Lyle Schemmerling\n */\n", + "fields" : { + "client_id" : { + "type" : "String" + }, + "client_secret" : { + "type" : "String" + }, + "grant_type" : { + "type" : "String" + }, + "password" : { + "type" : "String" + }, + "scope" : { + "type" : "String" + }, + "tenantId" : { + "type" : "String" + }, + "user_code" : { + "type" : "String" + }, + "username" : { + "type" : "String" + } + } +} \ No newline at end of file diff --git a/src/main/domain/io.fusionauth.domain.oauth2.ValidateDeviceRequest.json b/src/main/domain/io.fusionauth.domain.oauth2.ValidateDeviceRequest.json new file mode 100644 index 0000000..2af2139 --- /dev/null +++ b/src/main/domain/io.fusionauth.domain.oauth2.ValidateDeviceRequest.json @@ -0,0 +1,16 @@ +{ + "packageName" : "io.fusionauth.domain.oauth2", + "type" : "ValidateDeviceRequest", + "description" : "/**\n * The request object for validating an end-user provided user_code from the user-interaction of the Device Authorization Grant\n *\n * @author Lyle Schemmerling\n */\n", + "fields" : { + "client_id" : { + "type" : "String" + }, + "tenantId" : { + "type" : "UUID" + }, + "user_code" : { + "type" : "String" + } + } +} \ No newline at end of file From 5b45b30923beb351adab6c2e96bce9cc2764532d Mon Sep 17 00:00:00 2001 From: Lyle Schemmerling Date: Wed, 17 Dec 2025 13:38:53 -0700 Subject: [PATCH 8/9] and the domainNG files --- ...n.oauth2.AccessTokenIntrospectRequest.json | 23 ++++++++++ ...edentialsAccessTokenIntrospectRequest.json | 19 ++++++++ ....oauth2.ClientCredentialsGrantRequest.json | 31 +++++++++++++ ...h.domain.oauth2.DeviceApprovalRequest.json | 31 +++++++++++++ ...ain.oauth2.DeviceAuthorizationRequest.json | 27 ++++++++++++ ...in.oauth2.OAuthCodeAccessTokenRequest.json | 35 +++++++++++++++ ...auth2.OAuthCodePKCEAccessTokenRequest.json | 39 +++++++++++++++++ ...oauth2.RefreshTokenAccessTokenRequest.json | 39 +++++++++++++++++ ...domain.oauth2.RetrieveUserCodeRequest.json | 27 ++++++++++++ ...h2.RetrieveUserCodeUsingAPIKeyRequest.json | 19 ++++++++ ...th2.UserCredentialsAccessTokenRequest.json | 43 +++++++++++++++++++ ...h.domain.oauth2.ValidateDeviceRequest.json | 23 ++++++++++ 12 files changed, 356 insertions(+) create mode 100644 src/main/domainNG/io.fusionauth.domain.oauth2.AccessTokenIntrospectRequest.json create mode 100644 src/main/domainNG/io.fusionauth.domain.oauth2.ClientCredentialsAccessTokenIntrospectRequest.json create mode 100644 src/main/domainNG/io.fusionauth.domain.oauth2.ClientCredentialsGrantRequest.json create mode 100644 src/main/domainNG/io.fusionauth.domain.oauth2.DeviceApprovalRequest.json create mode 100644 src/main/domainNG/io.fusionauth.domain.oauth2.DeviceAuthorizationRequest.json create mode 100644 src/main/domainNG/io.fusionauth.domain.oauth2.OAuthCodeAccessTokenRequest.json create mode 100644 src/main/domainNG/io.fusionauth.domain.oauth2.OAuthCodePKCEAccessTokenRequest.json create mode 100644 src/main/domainNG/io.fusionauth.domain.oauth2.RefreshTokenAccessTokenRequest.json create mode 100644 src/main/domainNG/io.fusionauth.domain.oauth2.RetrieveUserCodeRequest.json create mode 100644 src/main/domainNG/io.fusionauth.domain.oauth2.RetrieveUserCodeUsingAPIKeyRequest.json create mode 100644 src/main/domainNG/io.fusionauth.domain.oauth2.UserCredentialsAccessTokenRequest.json create mode 100644 src/main/domainNG/io.fusionauth.domain.oauth2.ValidateDeviceRequest.json diff --git a/src/main/domainNG/io.fusionauth.domain.oauth2.AccessTokenIntrospectRequest.json b/src/main/domainNG/io.fusionauth.domain.oauth2.AccessTokenIntrospectRequest.json new file mode 100644 index 0000000..73d4885 --- /dev/null +++ b/src/main/domainNG/io.fusionauth.domain.oauth2.AccessTokenIntrospectRequest.json @@ -0,0 +1,23 @@ +{ + "className" : "io.fusionauth.domain.oauth2.AccessTokenIntrospectRequest", + "extends" : { }, + "fields" : { + "client_id" : { + "className" : "java.lang.String", + "type" : "String" + }, + "tenantId" : { + "className" : "java.lang.String", + "type" : "String" + }, + "token" : { + "className" : "java.lang.String", + "type" : "String" + } + }, + "imports" : [ "java.lang.String" ], + "interfaces" : [ ], + "objectType" : "Object", + "packageName" : "io.fusionauth.domain.oauth2", + "type" : "AccessTokenIntrospectRequest" +} \ No newline at end of file diff --git a/src/main/domainNG/io.fusionauth.domain.oauth2.ClientCredentialsAccessTokenIntrospectRequest.json b/src/main/domainNG/io.fusionauth.domain.oauth2.ClientCredentialsAccessTokenIntrospectRequest.json new file mode 100644 index 0000000..06a37b7 --- /dev/null +++ b/src/main/domainNG/io.fusionauth.domain.oauth2.ClientCredentialsAccessTokenIntrospectRequest.json @@ -0,0 +1,19 @@ +{ + "className" : "io.fusionauth.domain.oauth2.ClientCredentialsAccessTokenIntrospectRequest", + "extends" : { }, + "fields" : { + "tenantId" : { + "className" : "java.lang.String", + "type" : "String" + }, + "token" : { + "className" : "java.lang.String", + "type" : "String" + } + }, + "imports" : [ "java.lang.String" ], + "interfaces" : [ ], + "objectType" : "Object", + "packageName" : "io.fusionauth.domain.oauth2", + "type" : "ClientCredentialsAccessTokenIntrospectRequest" +} \ No newline at end of file diff --git a/src/main/domainNG/io.fusionauth.domain.oauth2.ClientCredentialsGrantRequest.json b/src/main/domainNG/io.fusionauth.domain.oauth2.ClientCredentialsGrantRequest.json new file mode 100644 index 0000000..7083ec0 --- /dev/null +++ b/src/main/domainNG/io.fusionauth.domain.oauth2.ClientCredentialsGrantRequest.json @@ -0,0 +1,31 @@ +{ + "className" : "io.fusionauth.domain.oauth2.ClientCredentialsGrantRequest", + "extends" : { }, + "fields" : { + "client_id" : { + "className" : "java.lang.String", + "type" : "String" + }, + "client_secret" : { + "className" : "java.lang.String", + "type" : "String" + }, + "grant_type" : { + "className" : "java.lang.String", + "type" : "String" + }, + "scope" : { + "className" : "java.lang.String", + "type" : "String" + }, + "tenantId" : { + "className" : "java.lang.String", + "type" : "String" + } + }, + "imports" : [ "java.lang.String" ], + "interfaces" : [ ], + "objectType" : "Object", + "packageName" : "io.fusionauth.domain.oauth2", + "type" : "ClientCredentialsGrantRequest" +} \ No newline at end of file diff --git a/src/main/domainNG/io.fusionauth.domain.oauth2.DeviceApprovalRequest.json b/src/main/domainNG/io.fusionauth.domain.oauth2.DeviceApprovalRequest.json new file mode 100644 index 0000000..93ca454 --- /dev/null +++ b/src/main/domainNG/io.fusionauth.domain.oauth2.DeviceApprovalRequest.json @@ -0,0 +1,31 @@ +{ + "className" : "io.fusionauth.domain.oauth2.DeviceApprovalRequest", + "extends" : { }, + "fields" : { + "client_id" : { + "className" : "java.lang.String", + "type" : "String" + }, + "client_secret" : { + "className" : "java.lang.String", + "type" : "String" + }, + "tenantId" : { + "className" : "java.util.UUID", + "type" : "UUID" + }, + "token" : { + "className" : "java.lang.String", + "type" : "String" + }, + "user_code" : { + "className" : "java.lang.String", + "type" : "String" + } + }, + "imports" : [ "java.lang.String", "java.util.UUID" ], + "interfaces" : [ ], + "objectType" : "Object", + "packageName" : "io.fusionauth.domain.oauth2", + "type" : "DeviceApprovalRequest" +} \ No newline at end of file diff --git a/src/main/domainNG/io.fusionauth.domain.oauth2.DeviceAuthorizationRequest.json b/src/main/domainNG/io.fusionauth.domain.oauth2.DeviceAuthorizationRequest.json new file mode 100644 index 0000000..6cbf75d --- /dev/null +++ b/src/main/domainNG/io.fusionauth.domain.oauth2.DeviceAuthorizationRequest.json @@ -0,0 +1,27 @@ +{ + "className" : "io.fusionauth.domain.oauth2.DeviceAuthorizationRequest", + "extends" : { }, + "fields" : { + "client_id" : { + "className" : "java.lang.String", + "type" : "String" + }, + "client_secret" : { + "className" : "java.lang.String", + "type" : "String" + }, + "scope" : { + "className" : "java.lang.String", + "type" : "String" + }, + "tenantId" : { + "className" : "java.util.UUID", + "type" : "UUID" + } + }, + "imports" : [ "java.lang.String", "java.util.UUID" ], + "interfaces" : [ ], + "objectType" : "Object", + "packageName" : "io.fusionauth.domain.oauth2", + "type" : "DeviceAuthorizationRequest" +} \ No newline at end of file diff --git a/src/main/domainNG/io.fusionauth.domain.oauth2.OAuthCodeAccessTokenRequest.json b/src/main/domainNG/io.fusionauth.domain.oauth2.OAuthCodeAccessTokenRequest.json new file mode 100644 index 0000000..4f0dfda --- /dev/null +++ b/src/main/domainNG/io.fusionauth.domain.oauth2.OAuthCodeAccessTokenRequest.json @@ -0,0 +1,35 @@ +{ + "className" : "io.fusionauth.domain.oauth2.OAuthCodeAccessTokenRequest", + "extends" : { }, + "fields" : { + "client_id" : { + "className" : "java.lang.String", + "type" : "String" + }, + "client_secret" : { + "className" : "java.lang.String", + "type" : "String" + }, + "code" : { + "className" : "java.lang.String", + "type" : "String" + }, + "grant_type" : { + "className" : "java.lang.String", + "type" : "String" + }, + "redirect_uri" : { + "className" : "java.lang.String", + "type" : "String" + }, + "tenantId" : { + "className" : "java.lang.String", + "type" : "String" + } + }, + "imports" : [ "java.lang.String" ], + "interfaces" : [ ], + "objectType" : "Object", + "packageName" : "io.fusionauth.domain.oauth2", + "type" : "OAuthCodeAccessTokenRequest" +} \ No newline at end of file diff --git a/src/main/domainNG/io.fusionauth.domain.oauth2.OAuthCodePKCEAccessTokenRequest.json b/src/main/domainNG/io.fusionauth.domain.oauth2.OAuthCodePKCEAccessTokenRequest.json new file mode 100644 index 0000000..636816c --- /dev/null +++ b/src/main/domainNG/io.fusionauth.domain.oauth2.OAuthCodePKCEAccessTokenRequest.json @@ -0,0 +1,39 @@ +{ + "className" : "io.fusionauth.domain.oauth2.OAuthCodePKCEAccessTokenRequest", + "extends" : { }, + "fields" : { + "client_id" : { + "className" : "java.lang.String", + "type" : "String" + }, + "client_secret" : { + "className" : "java.lang.String", + "type" : "String" + }, + "code" : { + "className" : "java.lang.String", + "type" : "String" + }, + "code_verifier" : { + "className" : "java.lang.String", + "type" : "String" + }, + "grant_type" : { + "className" : "java.lang.String", + "type" : "String" + }, + "redirect_uri" : { + "className" : "java.lang.String", + "type" : "String" + }, + "tenantId" : { + "className" : "java.util.UUID", + "type" : "UUID" + } + }, + "imports" : [ "java.lang.String", "java.util.UUID" ], + "interfaces" : [ ], + "objectType" : "Object", + "packageName" : "io.fusionauth.domain.oauth2", + "type" : "OAuthCodePKCEAccessTokenRequest" +} \ No newline at end of file diff --git a/src/main/domainNG/io.fusionauth.domain.oauth2.RefreshTokenAccessTokenRequest.json b/src/main/domainNG/io.fusionauth.domain.oauth2.RefreshTokenAccessTokenRequest.json new file mode 100644 index 0000000..a40a1e9 --- /dev/null +++ b/src/main/domainNG/io.fusionauth.domain.oauth2.RefreshTokenAccessTokenRequest.json @@ -0,0 +1,39 @@ +{ + "className" : "io.fusionauth.domain.oauth2.RefreshTokenAccessTokenRequest", + "extends" : { }, + "fields" : { + "client_id" : { + "className" : "java.lang.String", + "type" : "String" + }, + "client_secret" : { + "className" : "java.lang.String", + "type" : "String" + }, + "grant_type" : { + "className" : "java.lang.String", + "type" : "String" + }, + "refresh_token" : { + "className" : "java.lang.String", + "type" : "String" + }, + "scope" : { + "className" : "java.lang.String", + "type" : "String" + }, + "tenantId" : { + "className" : "java.util.UUID", + "type" : "UUID" + }, + "user_code" : { + "className" : "java.lang.String", + "type" : "String" + } + }, + "imports" : [ "java.lang.String", "java.util.UUID" ], + "interfaces" : [ ], + "objectType" : "Object", + "packageName" : "io.fusionauth.domain.oauth2", + "type" : "RefreshTokenAccessTokenRequest" +} \ No newline at end of file diff --git a/src/main/domainNG/io.fusionauth.domain.oauth2.RetrieveUserCodeRequest.json b/src/main/domainNG/io.fusionauth.domain.oauth2.RetrieveUserCodeRequest.json new file mode 100644 index 0000000..1b15919 --- /dev/null +++ b/src/main/domainNG/io.fusionauth.domain.oauth2.RetrieveUserCodeRequest.json @@ -0,0 +1,27 @@ +{ + "className" : "io.fusionauth.domain.oauth2.RetrieveUserCodeRequest", + "extends" : { }, + "fields" : { + "client_id" : { + "className" : "java.lang.String", + "type" : "String" + }, + "client_secret" : { + "className" : "java.lang.String", + "type" : "String" + }, + "tenantId" : { + "className" : "java.util.UUID", + "type" : "UUID" + }, + "user_code" : { + "className" : "java.lang.String", + "type" : "String" + } + }, + "imports" : [ "java.lang.String", "java.util.UUID" ], + "interfaces" : [ ], + "objectType" : "Object", + "packageName" : "io.fusionauth.domain.oauth2", + "type" : "RetrieveUserCodeRequest" +} \ No newline at end of file diff --git a/src/main/domainNG/io.fusionauth.domain.oauth2.RetrieveUserCodeUsingAPIKeyRequest.json b/src/main/domainNG/io.fusionauth.domain.oauth2.RetrieveUserCodeUsingAPIKeyRequest.json new file mode 100644 index 0000000..0f90131 --- /dev/null +++ b/src/main/domainNG/io.fusionauth.domain.oauth2.RetrieveUserCodeUsingAPIKeyRequest.json @@ -0,0 +1,19 @@ +{ + "className" : "io.fusionauth.domain.oauth2.RetrieveUserCodeUsingAPIKeyRequest", + "extends" : { }, + "fields" : { + "tenantId" : { + "className" : "java.util.UUID", + "type" : "UUID" + }, + "user_code" : { + "className" : "java.lang.String", + "type" : "String" + } + }, + "imports" : [ "java.util.UUID", "java.lang.String" ], + "interfaces" : [ ], + "objectType" : "Object", + "packageName" : "io.fusionauth.domain.oauth2", + "type" : "RetrieveUserCodeUsingAPIKeyRequest" +} \ No newline at end of file diff --git a/src/main/domainNG/io.fusionauth.domain.oauth2.UserCredentialsAccessTokenRequest.json b/src/main/domainNG/io.fusionauth.domain.oauth2.UserCredentialsAccessTokenRequest.json new file mode 100644 index 0000000..3403e30 --- /dev/null +++ b/src/main/domainNG/io.fusionauth.domain.oauth2.UserCredentialsAccessTokenRequest.json @@ -0,0 +1,43 @@ +{ + "className" : "io.fusionauth.domain.oauth2.UserCredentialsAccessTokenRequest", + "extends" : { }, + "fields" : { + "client_id" : { + "className" : "java.lang.String", + "type" : "String" + }, + "client_secret" : { + "className" : "java.lang.String", + "type" : "String" + }, + "grant_type" : { + "className" : "java.lang.String", + "type" : "String" + }, + "password" : { + "className" : "java.lang.String", + "type" : "String" + }, + "scope" : { + "className" : "java.lang.String", + "type" : "String" + }, + "tenantId" : { + "className" : "java.lang.String", + "type" : "String" + }, + "user_code" : { + "className" : "java.lang.String", + "type" : "String" + }, + "username" : { + "className" : "java.lang.String", + "type" : "String" + } + }, + "imports" : [ "java.lang.String" ], + "interfaces" : [ ], + "objectType" : "Object", + "packageName" : "io.fusionauth.domain.oauth2", + "type" : "UserCredentialsAccessTokenRequest" +} \ No newline at end of file diff --git a/src/main/domainNG/io.fusionauth.domain.oauth2.ValidateDeviceRequest.json b/src/main/domainNG/io.fusionauth.domain.oauth2.ValidateDeviceRequest.json new file mode 100644 index 0000000..7cae3b2 --- /dev/null +++ b/src/main/domainNG/io.fusionauth.domain.oauth2.ValidateDeviceRequest.json @@ -0,0 +1,23 @@ +{ + "className" : "io.fusionauth.domain.oauth2.ValidateDeviceRequest", + "extends" : { }, + "fields" : { + "client_id" : { + "className" : "java.lang.String", + "type" : "String" + }, + "tenantId" : { + "className" : "java.util.UUID", + "type" : "UUID" + }, + "user_code" : { + "className" : "java.lang.String", + "type" : "String" + } + }, + "imports" : [ "java.lang.String", "java.util.UUID" ], + "interfaces" : [ ], + "objectType" : "Object", + "packageName" : "io.fusionauth.domain.oauth2", + "type" : "ValidateDeviceRequest" +} \ No newline at end of file From 66c963ed0772dadc8a5e1116b9cc65a028e66d0c Mon Sep 17 00:00:00 2001 From: Lyle Schemmerling Date: Thu, 18 Dec 2025 12:34:59 -0700 Subject: [PATCH 9/9] handle GET on validateDeviceWithRequest with tenantId --- src/main/api/validateDeviceWithRequest.json | 4 +-- src/main/client/csharp.client.ftl | 27 +++++++++++++++++++-- src/main/client/go.client.ftl | 12 +++++++++ src/main/client/java.client.ftl | 14 +++++++++++ src/main/client/netcore.client.ftl | 12 +++++++++ src/main/client/php.client.ftl | 12 +++++++++ src/main/client/python.client.ftl | 12 +++++++++ src/main/client/ruby.client.ftl | 12 +++++++++ src/main/client/typescript.client.ftl | 12 +++++++++ 9 files changed, 113 insertions(+), 4 deletions(-) diff --git a/src/main/api/validateDeviceWithRequest.json b/src/main/api/validateDeviceWithRequest.json index 3dbc3cd..5a0ffcc 100644 --- a/src/main/api/validateDeviceWithRequest.json +++ b/src/main/api/validateDeviceWithRequest.json @@ -4,7 +4,7 @@ "Validates the end-user provided user_code from the user-interaction of the Device Authorization Grant.", "If you build your own activation form you should validate the user provided code prior to beginning the Authorization grant." ], - "method": "post", + "method": "get", "methodName": "validateDeviceWithRequest", "successResponse": "Void", "errorResponse": "Void", @@ -15,7 +15,7 @@ "comments": [ "The device validation request." ], - "type": "formBody", + "type": "queryBody", "javaType": "ValidateDeviceRequest" } ] diff --git a/src/main/client/csharp.client.ftl b/src/main/client/csharp.client.ftl index 18f7c9b..a3fe12d 100644 --- a/src/main/client/csharp.client.ftl +++ b/src/main/client/csharp.client.ftl @@ -107,7 +107,7 @@ namespace FusionAuth { [#assign formPost = false/] [#list api.params![] as param] - [#if param.type == "form"][#assign formPost = true/][/#if] + [#if param.type == "form" || param.type == "formBody"][#assign formPost = true/][/#if] [/#list] [#if formPost] Dictionary body = new Dictionary(); @@ -116,6 +116,29 @@ namespace FusionAuth body.Add("${param.name}", ${(param.constant?? && param.constant)?then("\""+param.value+"\"", param.name)}); [/#if] [/#list] + [#list api.params![] as param] + [#if param.type == "formBody"] + [#-- Lookup the domain object by javaType --] + [#list domain as d] + [#if d.type == param.javaType] + [#-- Iterate through all fields in the domain object --] + [#list d.fields as fieldName, field] + [#if field.type == "UUID"] + if (request.${fieldName} != null) { + body.Add("${fieldName}", request.${fieldName}.ToString()); + } + [#elseif field.type == "String"] + body.Add("${fieldName}", request.${fieldName}); + [#else] + if (request.${fieldName} != null) { + body.Add("${fieldName}", request.${fieldName}.ToString()); + } + [/#if] + [/#list] + [/#if] + [/#list] + [/#if] + [/#list] [/#if] return Start[#if api.anonymous??]Anonymous[/#if]<${global.convertType(api.successResponse, "csharp")}, ${global.convertType(api.errorResponse, "csharp")}>().Uri("${api.uri}") [#if api.authorization??] @@ -131,7 +154,7 @@ namespace FusionAuth [/#if] [/#list] [#if formPost] - .BodyHandler(new FormDataBodyHandler(body) + .BodyHandler(new FormDataBodyHandler(body)) [/#if] .${api.method?cap_first}() .Go(); diff --git a/src/main/client/go.client.ftl b/src/main/client/go.client.ftl index bb33adc..6aecd5e 100644 --- a/src/main/client/go.client.ftl +++ b/src/main/client/go.client.ftl @@ -290,6 +290,18 @@ func (c *FusionAuthClient) ${api.methodName?cap_first}WithContext(ctx context.Co [#else] WithParameter("${param.parameterName}", string(${(param.constant?? && param.constant)?then(param.value, global.convertValue(param.name, "go"))})). [/#if] + [#elseif param.type == "queryBody"] + [#list domain as d] + [#if d.type == param.javaType] + [#list d.fields as fieldName, field] + [#if field.type == "UUID" || field.type == "String"] + WithParameter("${fieldName}", request.${global.toCamelCase(fieldName)?cap_first}). + [#else] + WithParameter("${fieldName}", fmt.Sprintf("%v", request.${global.toCamelCase(fieldName)?cap_first})). + [/#if] + [/#list] + [/#if] + [/#list] [#elseif param.type == "body"] WithJSONBody(${global.convertValue(param.name, "go")}). [/#if] diff --git a/src/main/client/java.client.ftl b/src/main/client/java.client.ftl index 3b0c1e6..9e50cb3 100644 --- a/src/main/client/java.client.ftl +++ b/src/main/client/java.client.ftl @@ -419,6 +419,20 @@ public class FusionAuthClient { .urlParameter("${param.parameterName}", ${(param.constant?? && param.constant)?then(param.value, param.name)}) [#elseif param.type == "body"] .bodyHandler(new JSONBodyHandler(${param.name}, objectMapper())) + [#elseif param.type == "queryBody"] + [#-- Lookup the domain object by javaType --] + [#list domain as d] + [#if d.type == param.javaType] + [#-- Iterate through all fields in the domain object --] + [#list d.fields as fieldName, field] + [#if field.type == "String"] + .urlParameter("${fieldName}", request.${fieldName}) + [#else] + .urlParameter("${fieldName}", request.${fieldName} != null ? request.${fieldName}.toString() : null) + [/#if] + [/#list] + [/#if] + [/#list] [/#if] [/#list] [#if formPost] diff --git a/src/main/client/netcore.client.ftl b/src/main/client/netcore.client.ftl index a444701..b0eadac 100644 --- a/src/main/client/netcore.client.ftl +++ b/src/main/client/netcore.client.ftl @@ -131,6 +131,18 @@ namespace io.fusionauth { .withUriSegment(${(param.constant?? && param.constant)?then(param.value, param.name)}) [#elseif param.type == "urlParameter"] .withParameter("${param.parameterName}", ${(param.constant?? && param.constant)?then(param.value, param.name)}) + [#elseif param.type == "queryBody"] + [#list domain as d] + [#if d.type == param.javaType] + [#list d.fields as fieldName, field] + [#if field.type == "String"] + .withParameter("${fieldName}", request.${fieldName}) + [#else] + .withParameter("${fieldName}", request.${fieldName}?.ToString()) + [/#if] + [/#list] + [/#if] + [/#list] [#elseif param.type == "body"] .withJSONBody(${param.name}) [/#if] diff --git a/src/main/client/php.client.ftl b/src/main/client/php.client.ftl index aaf709f..87b7ecb 100644 --- a/src/main/client/php.client.ftl +++ b/src/main/client/php.client.ftl @@ -137,6 +137,18 @@ class FusionAuthClient ->urlSegment(${(param.constant?? && param.constant)?then(param.value, "$" + param.name)}) [#elseif param.type == "urlParameter"] ->urlParameter("${param.parameterName}", ${parameter_value(param)}) + [#elseif param.type == "queryBody"] + [#list domain as d] + [#if d.type == param.javaType] + [#list d.fields as fieldName, field] + [#if field.type == "String"] + ->urlParameter("${fieldName}", $request->${fieldName}) + [#else] + ->urlParameter("${fieldName}", $request->${fieldName} !== null ? (string)$request->${fieldName} : null) + [/#if] + [/#list] + [/#if] + [/#list] [#elseif param.type == "body"] ->bodyHandler(new JSONBodyHandler($${param.name})) [/#if] diff --git a/src/main/client/python.client.ftl b/src/main/client/python.client.ftl index 23c593a..be74bf1 100644 --- a/src/main/client/python.client.ftl +++ b/src/main/client/python.client.ftl @@ -88,6 +88,18 @@ class FusionAuthClient: .url_segment(${global.convertValue(param, "python")}) \ [#elseif param.type == "urlParameter"] .url_parameter('${param.parameterName}', self.convert_true_false(${global.convertValue(param, "python")})) \ + [#elseif param.type == "queryBody"] + [#list domain as d] + [#if d.type == param.javaType] + [#list d.fields as fieldName, field] + [#if field.type == "String"] + .url_parameter('${fieldName}', request.${fieldName}) \ + [#else] + .url_parameter('${fieldName}', str(request.${fieldName}) if request.${fieldName} is not None else None) \ + [/#if] + [/#list] + [/#if] + [/#list] [#elseif param.type == "body"] .body_handler(JSONBodyHandler(${camel_to_underscores(param.name)})) \ [/#if] diff --git a/src/main/client/ruby.client.ftl b/src/main/client/ruby.client.ftl index 2e649f4..235c779 100644 --- a/src/main/client/ruby.client.ftl +++ b/src/main/client/ruby.client.ftl @@ -96,6 +96,18 @@ module FusionAuth .url_segment(${(param.constant?? && param.constant)?then(param.value, camel_to_underscores(param.name))}) [#elseif param.type == "urlParameter"] .url_parameter('${param.parameterName}', ${(param.constant?? && param.constant)?then(param.value, camel_to_underscores(param.name?replace("end", "_end")))}) + [#elseif param.type == "queryBody"] + [#list domain as d] + [#if d.type == param.javaType] + [#list d.fields as fieldName, field] + [#if field.type == "String"] + .url_parameter('${fieldName}', request.${fieldName}) + [#else] + .url_parameter('${fieldName}', request.${fieldName}.nil? ? nil : request.${fieldName}.to_s) + [/#if] + [/#list] + [/#if] + [/#list] [#elseif param.type == "body"] .body_handler(FusionAuth::JSONBodyHandler.new(${camel_to_underscores(param.name)})) [/#if] diff --git a/src/main/client/typescript.client.ftl b/src/main/client/typescript.client.ftl index b888c7e..a83b8d5 100644 --- a/src/main/client/typescript.client.ftl +++ b/src/main/client/typescript.client.ftl @@ -117,6 +117,18 @@ export class FusionAuthClient { .withUriSegment(${(param.constant?? && param.constant)?then(param.value, param.name)}) [#elseif param.type == "urlParameter"] .withParameter('${param.parameterName}', ${(param.constant?? && param.constant)?then(param.value, param.name)}) + [#elseif param.type == "queryBody"] + [#list domain as d] + [#if d.type == param.javaType] + [#list d.fields as fieldName, field] + [#if field.type == "String"] + .withParameter('${fieldName}', request.${fieldName}) + [#else] + .withParameter('${fieldName}', request.${fieldName} != null ? request.${fieldName}.toString() : null) + [/#if] + [/#list] + [/#if] + [/#list] [#elseif param.type == "body"] .withJSONBody(${param.name}) [/#if]