Skip to content

fix: honor UseOauthSpecScope when marshaling OAuth2 connection scope - #837

Open
Asarew wants to merge 1 commit into
auth0:v1from
Asarew:fix/oauth2-space-delimited-scope
Open

fix: honor UseOauthSpecScope when marshaling OAuth2 connection scope#837
Asarew wants to merge 1 commit into
auth0:v1from
Asarew:fix/oauth2-space-delimited-scope

Conversation

@Asarew

@Asarew Asarew commented Jul 23, 2026

Copy link
Copy Markdown

🔧 Changes

Fixes ConnectionOptionsOAuth2.MarshalJSON to honor UseOauthSpecScope.

Before this change, MarshalJSON unconditionally emitted scope as a JSON array (["a","b","c"]), regardless of UseOauthSpecScope. Auth0's backend then persists that array as a comma-joined string and forwards it verbatim to the upstream IdP on /authorize, so RFC 6749-compliant IdPs (Keycloak, Ory, ...) reject the entire value as one invalid scope literal (invalid_scope: a,b,c). The UseOauthSpecScope field added in #699 was accepted by Auth0 and reflected in the dashboard checkbox, but never changed the wire format — it only affects per-authorize connection_scope extras server-side.

With this change, when UseOauthSpecScope == true, scope is marshaled as a raw space-delimited string ("a b c") — the form spec-compliant IdPs expect, and the same form the Auth0 dashboard produces when the "Separate scopes using a space" checkbox is on. When false or nil, the existing array behavior is preserved for back-compat.

Types and methods changed:

  • ConnectionOptionsOAuth2.MarshalJSON — split the scope write into two branches keyed on GetUseOauthSpecScope(). No new API, no removals.

UnmarshalJSON already accepts both the array and the string forms, so no change was needed on the read path — round-tripping is preserved.

📚 References

🔬 Testing

Automated: extended TestOAuth2Connection_MarshalJSON with two new cases (UseOauthSpecScope=true → string, UseOauthSpecScope=false → array) and added a {"scope":"foo bar baz"} row to TestOAuth2Connection_UnmarshalJSON to make the round-trip through the newly-emitted string form explicit.

$ go test -run TestOAuth2Connection ./management/ -v
=== RUN   TestOAuth2Connection_MarshalJSON
--- PASS: TestOAuth2Connection_MarshalJSON (0.00s)
=== RUN   TestOAuth2Connection_UnmarshalJSON
--- PASS: TestOAuth2Connection_UnmarshalJSON (0.00s)
PASS

Full connection marshal/unmarshal suite also passes (TestConnection.*Marshal|Unmarshal|TestGoogleOauth2Connection.*).

Manual end-to-end (against a real Auth0 tenant, on a custom social oauth2 connection to a Keycloak-backed IdP):

  1. Configure the connection with UseOauthSpecScope = true and scopes ["openid","profile","email"].
  2. With go-auth0 pinned to this branch, PATCH the connection.
  3. Inspect the connection in the Auth0 dashboard — Advanced Settings → Scope field now reads openid profile email (space-delimited) instead of openid,profile,email. The "Separate scopes using a space" checkbox is on.
  4. Initiate login via the connection — the upstream IdP receives scope=openid profile email and login completes. Previously it received scope=openid,profile,email and failed with invalid_scope.

📝 Checklist

  • All new/changed/fixed functionality is covered by tests (or N/A)
  • I have added documentation for all new/changed functionality (or N/A)

ConnectionOptionsOAuth2.MarshalJSON was always emitting scope as a JSON
array, regardless of UseOauthSpecScope. Auth0's backend then persists
that array as a comma-joined string and forwards it verbatim to the
upstream IdP, so RFC 6749-compliant IdPs (Keycloak, Ory, ...) reject the
scope as "a,b,c" — a single invalid literal.

When UseOauthSpecScope is true, marshal scope as a raw space-delimited
string per the OAuth 2.0 spec. When false or nil, keep the historical
array form for back-compat.

UnmarshalJSON already handled both wire shapes; no change needed there.

Related: auth0/terraform-provider-auth0#1656
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant