diff --git a/authentication/oauth.go b/authentication/oauth.go index 4e64f6f0..7e4f06c2 100644 --- a/authentication/oauth.go +++ b/authentication/oauth.go @@ -150,6 +150,10 @@ func (o *OAuth) LoginWithClientCredentials(ctx context.Context, body oauth.Login "audience": []string{body.Audience}, } + if body.Organization != "" { + data.Set("organization", body.Organization) + } + err = o.addClientAuthentication(body.ClientAuthentication, data, true) if err != nil { diff --git a/authentication/oauth/oauth.go b/authentication/oauth/oauth.go index c015707a..35d123b4 100644 --- a/authentication/oauth/oauth.go +++ b/authentication/oauth/oauth.go @@ -83,6 +83,8 @@ type LoginWithClientCredentialsRequest struct { Audience string // Extra parameters to be merged into the request body. Values set here will override any existing values. ExtraParameters map[string]string + // And organization name or ID. When included, the access token will include the `org_id` or `org_name` claim. + Organization string } // RefreshTokenRequest defines the request body for logging in with Authorization Code grant. diff --git a/authentication/oauth_test.go b/authentication/oauth_test.go index 434803be..25d1f31c 100644 --- a/authentication/oauth_test.go +++ b/authentication/oauth_test.go @@ -253,6 +253,22 @@ func TestLoginWithClientCredentials(t *testing.T) { assert.ErrorContains(t, err, "Unsupported client assertion algorithm \"invalid-alg\" provided") }) + + t.Run("Should support passing an organization", func(t *testing.T) { + configureHTTPTestRecordings(t) + + tokenSet, err := authAPI.OAuth.LoginWithClientCredentials(context.Background(), oauth.LoginWithClientCredentialsRequest{ + ClientAuthentication: oauth.ClientAuthentication{ + ClientSecret: clientSecret, + }, + Audience: "my-api", + Organization: "org_test", + }, oauth.IDTokenValidationOptions{}) + + assert.NoError(t, err) + assert.NotEmpty(t, tokenSet.AccessToken) + assert.Equal(t, "Bearer", tokenSet.TokenType) + }) } func TestRefreshToken(t *testing.T) { diff --git a/management/client_grant.go b/management/client_grant.go index 8b2fde67..cd907fd6 100644 --- a/management/client_grant.go +++ b/management/client_grant.go @@ -15,7 +15,15 @@ type ClientGrant struct { // The audience. Audience *string `json:"audience,omitempty"` - Scope []string `json:"scope"` + Scope []string `json:"scope,omitempty"` + + // If enabled, any organization can be used with this grant. + // If disabled (default), the grant must be explicitly assigned to the desired organizations. + AllowAnyOrganization *bool `json:"allow_any_organization,omitempty"` + + // Defines whether organizations can be used with client credentials exchanges for this grant. + // Can be one of `deny`, `allow`, or `require`. Defaults to `deny` when not defined. + OrganizationUsage *string `json:"organization_usage,omitempty"` } // ClientGrantList is a list of ClientGrants. @@ -87,3 +95,12 @@ func (m *ClientGrantManager) List(ctx context.Context, opts ...RequestOption) (g err = m.management.Request(ctx, "GET", m.management.URI("client-grants"), &gs, applyListDefaults(opts)) return } + +// Organizations lists client grants associated to an organization. +// +// This method forces the `include_totals=true` and defaults to `per_page=50` if +// not provided. +func (m *ClientGrantManager) Organizations(ctx context.Context, id string, opts ...RequestOption) (o *OrganizationList, err error) { + err = m.management.Request(ctx, "GET", m.management.URI("client-grants", id, "organizations"), &o, applyListDefaults(opts)) + return +} diff --git a/management/client_grant_test.go b/management/client_grant_test.go index b3634461..c7e2ec0f 100644 --- a/management/client_grant_test.go +++ b/management/client_grant_test.go @@ -6,6 +6,8 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + + "github.com/auth0/go-auth0" ) func TestClientGrantManager_Create(t *testing.T) { @@ -31,7 +33,7 @@ func TestClientGrantManager_Create(t *testing.T) { func TestClientGrantManager_Read(t *testing.T) { configureHTTPTestRecordings(t) - expectedClientGrant := givenAClientGrant(t) + expectedClientGrant := givenAClientGrant(t, false) actualClientGrant, err := api.ClientGrant.Read(context.Background(), expectedClientGrant.GetID()) @@ -44,7 +46,7 @@ func TestClientGrantManager_Read(t *testing.T) { func TestClientGrantManager_Update(t *testing.T) { configureHTTPTestRecordings(t) - expectedClientGrant := givenAClientGrant(t) + expectedClientGrant := givenAClientGrant(t, false) clientGrantID := expectedClientGrant.GetID() @@ -64,7 +66,7 @@ func TestClientGrantManager_Update(t *testing.T) { func TestClientGrantManager_Delete(t *testing.T) { configureHTTPTestRecordings(t) - expectedClientGrant := givenAClientGrant(t) + expectedClientGrant := givenAClientGrant(t, false) err := api.ClientGrant.Delete(context.Background(), expectedClientGrant.GetID()) assert.NoError(t, err) @@ -77,7 +79,7 @@ func TestClientGrantManager_Delete(t *testing.T) { func TestClientGrantManager_List(t *testing.T) { configureHTTPTestRecordings(t) - expectedClientGrant := givenAClientGrant(t) + expectedClientGrant := givenAClientGrant(t, false) clientGrantList, err := api.ClientGrant.List( context.Background(), @@ -88,7 +90,21 @@ func TestClientGrantManager_List(t *testing.T) { assert.Equal(t, len(clientGrantList.ClientGrants), 1) } -func givenAClientGrant(t *testing.T) (clientGrant *ClientGrant) { +func TestClientGrantManager_Organizations(t *testing.T) { + configureHTTPTestRecordings(t) + + org := givenAnOrganization(t) + clientGrant := givenAClientGrant(t, true) + + err := api.Organization.AssociateClientGrant(context.Background(), org.GetID(), clientGrant.GetID()) + require.NoError(t, err) + + associatedOrg, err := api.ClientGrant.Organizations(context.Background(), clientGrant.GetID()) + require.NoError(t, err) + assert.Equal(t, org.GetID(), associatedOrg.Organizations[0].GetID()) +} + +func givenAClientGrant(t *testing.T, allowOrganizations bool) (clientGrant *ClientGrant) { t.Helper() client := givenAClient(t) @@ -100,6 +116,11 @@ func givenAClientGrant(t *testing.T) (clientGrant *ClientGrant) { Scope: []string{"create:resource"}, } + if allowOrganizations { + clientGrant.AllowAnyOrganization = auth0.Bool(true) + clientGrant.OrganizationUsage = auth0.String("allow") + } + err := api.ClientGrant.Create(context.Background(), clientGrant) require.NoError(t, err) diff --git a/management/management.gen.go b/management/management.gen.go index d3b6fec1..fafebfd8 100644 --- a/management/management.gen.go +++ b/management/management.gen.go @@ -1763,6 +1763,14 @@ func (c *ClientAuthenticationMethods) String() string { return Stringify(c) } +// GetAllowAnyOrganization returns the AllowAnyOrganization field if it's non-nil, zero value otherwise. +func (c *ClientGrant) GetAllowAnyOrganization() bool { + if c == nil || c.AllowAnyOrganization == nil { + return false + } + return *c.AllowAnyOrganization +} + // GetAudience returns the Audience field if it's non-nil, zero value otherwise. func (c *ClientGrant) GetAudience() string { if c == nil || c.Audience == nil { @@ -1787,6 +1795,14 @@ func (c *ClientGrant) GetID() string { return *c.ID } +// GetOrganizationUsage returns the OrganizationUsage field if it's non-nil, zero value otherwise. +func (c *ClientGrant) GetOrganizationUsage() string { + if c == nil || c.OrganizationUsage == nil { + return "" + } + return *c.OrganizationUsage +} + // String returns a string representation of ClientGrant. func (c *ClientGrant) String() string { return Stringify(c) diff --git a/management/management.gen_test.go b/management/management.gen_test.go index 221029af..8d4565a2 100644 --- a/management/management.gen_test.go +++ b/management/management.gen_test.go @@ -2137,6 +2137,16 @@ func TestClientAuthenticationMethods_String(t *testing.T) { } } +func TestClientGrant_GetAllowAnyOrganization(tt *testing.T) { + var zeroValue bool + c := &ClientGrant{AllowAnyOrganization: &zeroValue} + c.GetAllowAnyOrganization() + c = &ClientGrant{} + c.GetAllowAnyOrganization() + c = nil + c.GetAllowAnyOrganization() +} + func TestClientGrant_GetAudience(tt *testing.T) { var zeroValue string c := &ClientGrant{Audience: &zeroValue} @@ -2167,6 +2177,16 @@ func TestClientGrant_GetID(tt *testing.T) { c.GetID() } +func TestClientGrant_GetOrganizationUsage(tt *testing.T) { + var zeroValue string + c := &ClientGrant{OrganizationUsage: &zeroValue} + c.GetOrganizationUsage() + c = &ClientGrant{} + c.GetOrganizationUsage() + c = nil + c.GetOrganizationUsage() +} + func TestClientGrant_String(t *testing.T) { var rawJSON json.RawMessage v := &ClientGrant{} diff --git a/management/organization.go b/management/organization.go index fc480984..3fcd44a6 100644 --- a/management/organization.go +++ b/management/organization.go @@ -379,3 +379,26 @@ func (m *OrganizationManager) DeleteMemberRoles(ctx context.Context, id string, err = m.management.Request(ctx, "DELETE", m.management.URI("organizations", id, "members", memberID, "roles"), &body, opts...) return } + +// ClientGrants retrieves the client grants assigned to an organization. +func (m *OrganizationManager) ClientGrants(ctx context.Context, id string, opts ...RequestOption) (g *ClientGrantList, err error) { + err = m.management.Request(ctx, "GET", m.management.URI("organizations", id, "client-grants"), &g, applyListDefaults(opts)) + return +} + +// AssociateClientGrant assigns a client grant to an organization. +func (m *OrganizationManager) AssociateClientGrant(ctx context.Context, id string, grantID string, opts ...RequestOption) (err error) { + body := struct { + GrantID string `json:"grant_id"` + }{ + GrantID: grantID, + } + err = m.management.Request(ctx, "POST", m.management.URI("organizations", id, "client-grants"), &body, applyListDefaults(opts)) + return +} + +// RemoveClientGrant removes a client grant from an organization. +func (m *OrganizationManager) RemoveClientGrant(ctx context.Context, id string, grantID string, opts ...RequestOption) (err error) { + err = m.management.Request(ctx, "DELETE", m.management.URI("organizations", id, "client-grants", grantID), nil, applyListDefaults(opts)) + return +} diff --git a/management/organization_test.go b/management/organization_test.go index 05665e78..d7c42d81 100644 --- a/management/organization_test.go +++ b/management/organization_test.go @@ -366,6 +366,28 @@ func TestOrganizationManager_MemberRoles(t *testing.T) { assert.Len(t, roles.Roles, 0) } +func TestOrganizationManager_ClientGrants(t *testing.T) { + configureHTTPTestRecordings(t) + + org := givenAnOrganization(t) + clientGrant := givenAClientGrant(t, true) + + err := api.Organization.AssociateClientGrant(context.Background(), org.GetID(), clientGrant.GetID()) + require.NoError(t, err) + + associatedGrants, err := api.Organization.ClientGrants(context.Background(), org.GetID()) + require.NoError(t, err) + assert.Len(t, associatedGrants.ClientGrants, 1) + assert.Equal(t, clientGrant.GetID(), associatedGrants.ClientGrants[0].GetID()) + + err = api.Organization.RemoveClientGrant(context.Background(), org.GetID(), clientGrant.GetID()) + require.NoError(t, err) + + associatedGrants, err = api.Organization.ClientGrants(context.Background(), org.GetID()) + require.NoError(t, err) + assert.Len(t, associatedGrants.ClientGrants, 0) +} + func givenAnOrganization(t *testing.T) *Organization { org := &Organization{ Name: auth0.String(fmt.Sprintf("test-organization%v", rand.Intn(999))), diff --git a/test/data/recordings/TestClientGrantManager_Organizations.yaml b/test/data/recordings/TestClientGrantManager_Organizations.yaml new file mode 100644 index 00000000..483db72a --- /dev/null +++ b/test/data/recordings/TestClientGrantManager_Organizations.yaml @@ -0,0 +1,359 @@ +--- +version: 2 +interactions: + - id: 0 + request: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 122 + transfer_encoding: [] + trailer: {} + host: go-auth0-dev.eu.auth0.com + remote_addr: "" + request_uri: "" + body: | + {"name":"test-organization248","display_name":"Test Organization","branding":{"logo_url":"https://example.com/logo.gif"}} + form: {} + headers: + Content-Type: + - application/json + User-Agent: + - Go-Auth0/latest + url: https://go-auth0-dev.eu.auth0.com/api/v2/organizations + method: POST + response: + proto: HTTP/2.0 + proto_major: 2 + proto_minor: 0 + transfer_encoding: [] + trailer: {} + content_length: 149 + uncompressed: false + body: '{"name":"test-organization248","display_name":"Test Organization","branding":{"logo_url":"https://example.com/logo.gif"},"id":"org_OjbL69ZRTlpNCzsC"}' + headers: + Content-Type: + - application/json; charset=utf-8 + status: 201 Created + code: 201 + duration: 629.701542ms + - id: 1 + request: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 1125 + transfer_encoding: [] + trailer: {} + host: go-auth0-dev.eu.auth0.com + remote_addr: "" + request_uri: "" + body: | + {"name":"Test Client (Nov 8 16:32:06.260)","description":"This is just a test client.","jwt_configuration":{"alg":"RS256"},"organization_usage":"allow","client_authentication_methods":{"private_key_jwt":{"credentials":[{"name":"Test Credential (Nov 8 16:32:06.261)","credential_type":"public_key","pem":"-----BEGIN PUBLIC KEY-----\nMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAua6LXMfgDE/tDdkOL1Oe\n3oWUwg1r4dSTg9L7RCcI5hItUzmkVofHtWN0H4CH2lm2ANmaJUsnhzctYowYW2+R\ntHvU9afTmtbdhpy993972hUqZSYLsE3iGziphYkOKVsqq38+VRH3TNg93zSLoRao\nJnTTkMXseVqiyqYRmFN8+gQQoEclHSGPUWQG5XMZ+hhuXeFyo+Yw/qbZWca/6/2I\n3rsca9jXR1alhxhHrXrg8N4Dm3gBgGbmiht6YYYT2Tyl1OqB9+iOI/9D7dfoCF6X\nAWJXRE454cmC8k8oucpjZVpflA+ocKshwPDR6YTLQYbXYiaWxEoaz0QGUErNQBnG\nI+sr9jDY3ua/s6HF6h0qyi/HVZH4wx+m4CtOfJoYTjrGBbaRszzUxhtSN2/MhXDu\n+a35q9/2zcu/3fjkkfVvGUt+NyyiYOKQ9vsJC1g/xxdUWtowjNwjfZE2zcG4usi8\nr38Bp0lmiipAsMLduZM/D5dFXkRdWCBNDfULmmg/4nv2wwjbjQuLemAMh7mmrztW\ni/85WMnjKQZT8NqS43pmgyIzg1gK1neMqdS90YmQ/PvJ36qALxCs245w1JpN9BAL\nJbwxCg/dbmKT7PalfWrksx9hGcJxtGqebldaOpw+5GVIPxxtC1C0gVr9BKeiDS3f\naibASY5pIRiKENmbZELDtucCAwEAAQ==\n-----END PUBLIC KEY-----"}]}}} + form: {} + headers: + Content-Type: + - application/json + User-Agent: + - Go-Auth0/latest + url: https://go-auth0-dev.eu.auth0.com/api/v2/clients + method: POST + response: + proto: HTTP/2.0 + proto_major: 2 + proto_minor: 0 + transfer_encoding: [] + trailer: {} + content_length: -1 + uncompressed: false + body: '{"name":"Test Client (Nov 8 16:32:06.260)","description":"This is just a test client.","client_id":"jsOdQrWgCpGCXsZ596k45Yba0pEXkmDG","client_secret":"[REDACTED]","is_first_party":true,"is_token_endpoint_ip_header_trusted":false,"oidc_conformant":false,"jwt_configuration":{"secret_encoded":false,"alg":"RS256"},"signing_keys":[{"cert":"[REDACTED]"}],"sso_disabled":false,"grant_types":["authorization_code","implicit","refresh_token","client_credentials"],"custom_login_page_on":true,"refresh_token":{"rotation_type":"non-rotating","expiration_type":"non-expiring","leeway":0,"token_lifetime":2592000,"infinite_token_lifetime":true,"infinite_idle_token_lifetime":true,"idle_token_lifetime":1296000},"organization_usage":"allow","client_authentication_methods":{"private_key_jwt":{"credentials":[{"id":"cred_jL72fJDnj3nNGsbCoYvruj","name":"Test Credential (Nov 8 16:32:06.261)","kid":"4e7yYf0TKdyTLbVnpq2wLN6mZ8t7eb9UJkMksyHj9iU","credential_type":"public_key","alg":"RS256","created_at":"2023-11-08T16:32:06.505Z","updated_at":"2023-11-08T16:32:06.505Z"}]}}}' + headers: + Content-Type: + - application/json; charset=utf-8 + status: 201 Created + code: 201 + duration: 463.235209ms + - id: 2 + request: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 239 + transfer_encoding: [] + trailer: {} + host: go-auth0-dev.eu.auth0.com + remote_addr: "" + request_uri: "" + body: | + {"name":"Test Resource Server (Nov 8 16:32:06.726)","identifier":"https://api.example.com/","scopes":[{"value":"create:resource","description":"Create Resource"}],"signing_alg":"HS256","token_lifetime":7200,"token_lifetime_for_web":3600} + form: {} + headers: + Content-Type: + - application/json + User-Agent: + - Go-Auth0/latest + url: https://go-auth0-dev.eu.auth0.com/api/v2/resource-servers + method: POST + response: + proto: HTTP/2.0 + proto_major: 2 + proto_minor: 0 + transfer_encoding: [] + trailer: {} + content_length: 407 + uncompressed: false + body: '{"id":"654bb8060c032297bf07ecaf","name":"Test Resource Server (Nov 8 16:32:06.726)","identifier":"https://api.example.com/","scopes":[{"value":"create:resource","description":"Create Resource"}],"signing_alg":"HS256","allow_offline_access":false,"token_lifetime":7200,"token_lifetime_for_web":3600,"skip_consent_for_verifiable_first_party_clients":false}' + headers: + Content-Type: + - application/json; charset=utf-8 + status: 201 Created + code: 201 + duration: 266.637208ms + - id: 3 + request: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 174 + transfer_encoding: [] + trailer: {} + host: go-auth0-dev.eu.auth0.com + remote_addr: "" + request_uri: "" + body: | + {"client_id":"jsOdQrWgCpGCXsZ596k45Yba0pEXkmDG","audience":"https://api.example.com/","scope":["create:resource"],"allow_any_organization":true,"organization_usage":"allow"} + form: {} + headers: + Content-Type: + - application/json + User-Agent: + - Go-Auth0/latest + url: https://go-auth0-dev.eu.auth0.com/api/v2/client-grants + method: POST + response: + proto: HTTP/2.0 + proto_major: 2 + proto_minor: 0 + transfer_encoding: [] + trailer: {} + content_length: 201 + uncompressed: false + body: '{"id":"cgr_MyWeQ2whciOYISER","client_id":"jsOdQrWgCpGCXsZ596k45Yba0pEXkmDG","audience":"https://api.example.com/","scope":["create:resource"],"organization_usage":"allow","allow_any_organization":true}' + headers: + Content-Type: + - application/json; charset=utf-8 + status: 201 Created + code: 201 + duration: 278.980709ms + - id: 4 + request: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 36 + transfer_encoding: [] + trailer: {} + host: go-auth0-dev.eu.auth0.com + remote_addr: "" + request_uri: "" + body: | + {"grant_id":"cgr_MyWeQ2whciOYISER"} + form: {} + headers: + Content-Type: + - application/json + User-Agent: + - Go-Auth0/latest + url: https://go-auth0-dev.eu.auth0.com/api/v2/organizations/org_OjbL69ZRTlpNCzsC/client-grants?include_totals=true&per_page=50 + method: POST + response: + proto: HTTP/2.0 + proto_major: 2 + proto_minor: 0 + transfer_encoding: [] + trailer: {} + content_length: 148 + uncompressed: false + body: '{"grant_id":"cgr_MyWeQ2whciOYISER","client_id":"jsOdQrWgCpGCXsZ596k45Yba0pEXkmDG","audience":"https://api.example.com/","scope":["create:resource"]}' + headers: + Content-Type: + - application/json; charset=utf-8 + status: 201 Created + code: 201 + duration: 278.988083ms + - id: 5 + request: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 5 + transfer_encoding: [] + trailer: {} + host: go-auth0-dev.eu.auth0.com + remote_addr: "" + request_uri: "" + body: | + null + form: {} + headers: + Content-Type: + - application/json + User-Agent: + - Go-Auth0/latest + url: https://go-auth0-dev.eu.auth0.com/api/v2/client-grants/cgr_MyWeQ2whciOYISER/organizations?include_totals=true&per_page=50 + method: GET + response: + proto: HTTP/2.0 + proto_major: 2 + proto_minor: 0 + transfer_encoding: [] + trailer: {} + content_length: -1 + uncompressed: true + body: '{"organizations":[{"id":"org_OjbL69ZRTlpNCzsC","name":"test-organization248","display_name":"Test Organization","branding":{"logo_url":"https://example.com/logo.gif"}}],"start":0,"limit":50,"total":1}' + headers: + Content-Type: + - application/json; charset=utf-8 + status: 200 OK + code: 200 + duration: 269.523041ms + - id: 6 + request: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 0 + transfer_encoding: [] + trailer: {} + host: go-auth0-dev.eu.auth0.com + remote_addr: "" + request_uri: "" + body: "" + form: {} + headers: + Content-Type: + - application/json + User-Agent: + - Go-Auth0/latest + url: https://go-auth0-dev.eu.auth0.com/api/v2/client-grants/cgr_MyWeQ2whciOYISER + method: DELETE + response: + proto: HTTP/2.0 + proto_major: 2 + proto_minor: 0 + transfer_encoding: [] + trailer: {} + content_length: 0 + uncompressed: false + body: "" + headers: + Content-Type: + - application/json; charset=utf-8 + status: 204 No Content + code: 204 + duration: 348.420625ms + - id: 7 + request: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 0 + transfer_encoding: [] + trailer: {} + host: go-auth0-dev.eu.auth0.com + remote_addr: "" + request_uri: "" + body: "" + form: {} + headers: + Content-Type: + - application/json + User-Agent: + - Go-Auth0/latest + url: https://go-auth0-dev.eu.auth0.com/api/v2/resource-servers/654bb8060c032297bf07ecaf + method: DELETE + response: + proto: HTTP/2.0 + proto_major: 2 + proto_minor: 0 + transfer_encoding: [] + trailer: {} + content_length: 0 + uncompressed: false + body: "" + headers: + Content-Type: + - application/json; charset=utf-8 + status: 204 No Content + code: 204 + duration: 423.452375ms + - id: 8 + request: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 0 + transfer_encoding: [] + trailer: {} + host: go-auth0-dev.eu.auth0.com + remote_addr: "" + request_uri: "" + body: "" + form: {} + headers: + Content-Type: + - application/json + User-Agent: + - Go-Auth0/latest + url: https://go-auth0-dev.eu.auth0.com/api/v2/clients/jsOdQrWgCpGCXsZ596k45Yba0pEXkmDG + method: DELETE + response: + proto: HTTP/2.0 + proto_major: 2 + proto_minor: 0 + transfer_encoding: [] + trailer: {} + content_length: 0 + uncompressed: false + body: "" + headers: + Content-Type: + - application/json; charset=utf-8 + status: 204 No Content + code: 204 + duration: 511.401708ms + - id: 9 + request: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 0 + transfer_encoding: [] + trailer: {} + host: go-auth0-dev.eu.auth0.com + remote_addr: "" + request_uri: "" + body: "" + form: {} + headers: + Content-Type: + - application/json + User-Agent: + - Go-Auth0/latest + url: https://go-auth0-dev.eu.auth0.com/api/v2/organizations/org_OjbL69ZRTlpNCzsC + method: DELETE + response: + proto: HTTP/2.0 + proto_major: 2 + proto_minor: 0 + transfer_encoding: [] + trailer: {} + content_length: 0 + uncompressed: false + body: "" + headers: + Content-Type: + - application/json; charset=utf-8 + status: 204 No Content + code: 204 + duration: 241.841375ms diff --git a/test/data/recordings/TestOrganizationManager_ClientGrants.yaml b/test/data/recordings/TestOrganizationManager_ClientGrants.yaml new file mode 100644 index 00000000..c07c8f7b --- /dev/null +++ b/test/data/recordings/TestOrganizationManager_ClientGrants.yaml @@ -0,0 +1,430 @@ +--- +version: 2 +interactions: + - id: 0 + request: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 122 + transfer_encoding: [] + trailer: {} + host: go-auth0-dev.eu.auth0.com + remote_addr: "" + request_uri: "" + body: | + {"name":"test-organization978","display_name":"Test Organization","branding":{"logo_url":"https://example.com/logo.gif"}} + form: {} + headers: + Content-Type: + - application/json + User-Agent: + - Go-Auth0/latest + url: https://go-auth0-dev.eu.auth0.com/api/v2/organizations + method: POST + response: + proto: HTTP/2.0 + proto_major: 2 + proto_minor: 0 + transfer_encoding: [] + trailer: {} + content_length: 149 + uncompressed: false + body: '{"name":"test-organization978","display_name":"Test Organization","branding":{"logo_url":"https://example.com/logo.gif"},"id":"org_kRblHAs7YQpHZNTA"}' + headers: + Content-Type: + - application/json; charset=utf-8 + status: 201 Created + code: 201 + duration: 696.817875ms + - id: 1 + request: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 1125 + transfer_encoding: [] + trailer: {} + host: go-auth0-dev.eu.auth0.com + remote_addr: "" + request_uri: "" + body: | + {"name":"Test Client (Nov 8 16:31:36.568)","description":"This is just a test client.","jwt_configuration":{"alg":"RS256"},"organization_usage":"allow","client_authentication_methods":{"private_key_jwt":{"credentials":[{"name":"Test Credential (Nov 8 16:31:36.569)","credential_type":"public_key","pem":"-----BEGIN PUBLIC KEY-----\nMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAua6LXMfgDE/tDdkOL1Oe\n3oWUwg1r4dSTg9L7RCcI5hItUzmkVofHtWN0H4CH2lm2ANmaJUsnhzctYowYW2+R\ntHvU9afTmtbdhpy993972hUqZSYLsE3iGziphYkOKVsqq38+VRH3TNg93zSLoRao\nJnTTkMXseVqiyqYRmFN8+gQQoEclHSGPUWQG5XMZ+hhuXeFyo+Yw/qbZWca/6/2I\n3rsca9jXR1alhxhHrXrg8N4Dm3gBgGbmiht6YYYT2Tyl1OqB9+iOI/9D7dfoCF6X\nAWJXRE454cmC8k8oucpjZVpflA+ocKshwPDR6YTLQYbXYiaWxEoaz0QGUErNQBnG\nI+sr9jDY3ua/s6HF6h0qyi/HVZH4wx+m4CtOfJoYTjrGBbaRszzUxhtSN2/MhXDu\n+a35q9/2zcu/3fjkkfVvGUt+NyyiYOKQ9vsJC1g/xxdUWtowjNwjfZE2zcG4usi8\nr38Bp0lmiipAsMLduZM/D5dFXkRdWCBNDfULmmg/4nv2wwjbjQuLemAMh7mmrztW\ni/85WMnjKQZT8NqS43pmgyIzg1gK1neMqdS90YmQ/PvJ36qALxCs245w1JpN9BAL\nJbwxCg/dbmKT7PalfWrksx9hGcJxtGqebldaOpw+5GVIPxxtC1C0gVr9BKeiDS3f\naibASY5pIRiKENmbZELDtucCAwEAAQ==\n-----END PUBLIC KEY-----"}]}}} + form: {} + headers: + Content-Type: + - application/json + User-Agent: + - Go-Auth0/latest + url: https://go-auth0-dev.eu.auth0.com/api/v2/clients + method: POST + response: + proto: HTTP/2.0 + proto_major: 2 + proto_minor: 0 + transfer_encoding: [] + trailer: {} + content_length: -1 + uncompressed: false + body: '{"name":"Test Client (Nov 8 16:31:36.568)","description":"This is just a test client.","client_id":"rZkYzbKzqfoJ9I5jWY0OLlR3jtGGQBQh","client_secret":"[REDACTED]","is_first_party":true,"is_token_endpoint_ip_header_trusted":false,"oidc_conformant":false,"jwt_configuration":{"secret_encoded":false,"alg":"RS256"},"signing_keys":[{"cert":"[REDACTED]"}],"sso_disabled":false,"grant_types":["authorization_code","implicit","refresh_token","client_credentials"],"custom_login_page_on":true,"refresh_token":{"rotation_type":"non-rotating","expiration_type":"non-expiring","leeway":0,"token_lifetime":2592000,"infinite_token_lifetime":true,"infinite_idle_token_lifetime":true,"idle_token_lifetime":1296000},"organization_usage":"allow","client_authentication_methods":{"private_key_jwt":{"credentials":[{"id":"cred_12H9rPQfvfhfbi7XQWHC3r","name":"Test Credential (Nov 8 16:31:36.569)","kid":"4e7yYf0TKdyTLbVnpq2wLN6mZ8t7eb9UJkMksyHj9iU","credential_type":"public_key","alg":"RS256","created_at":"2023-11-08T16:31:36.813Z","updated_at":"2023-11-08T16:31:36.813Z"}]}}}' + headers: + Content-Type: + - application/json; charset=utf-8 + status: 201 Created + code: 201 + duration: 683.416ms + - id: 2 + request: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 239 + transfer_encoding: [] + trailer: {} + host: go-auth0-dev.eu.auth0.com + remote_addr: "" + request_uri: "" + body: | + {"name":"Test Resource Server (Nov 8 16:31:37.254)","identifier":"https://api.example.com/","scopes":[{"value":"create:resource","description":"Create Resource"}],"signing_alg":"HS256","token_lifetime":7200,"token_lifetime_for_web":3600} + form: {} + headers: + Content-Type: + - application/json + User-Agent: + - Go-Auth0/latest + url: https://go-auth0-dev.eu.auth0.com/api/v2/resource-servers + method: POST + response: + proto: HTTP/2.0 + proto_major: 2 + proto_minor: 0 + transfer_encoding: [] + trailer: {} + content_length: 407 + uncompressed: false + body: '{"id":"654bb7e9eb2d17b5d2f4909f","name":"Test Resource Server (Nov 8 16:31:37.254)","identifier":"https://api.example.com/","scopes":[{"value":"create:resource","description":"Create Resource"}],"signing_alg":"HS256","allow_offline_access":false,"token_lifetime":7200,"token_lifetime_for_web":3600,"skip_consent_for_verifiable_first_party_clients":false}' + headers: + Content-Type: + - application/json; charset=utf-8 + status: 201 Created + code: 201 + duration: 520.929375ms + - id: 3 + request: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 174 + transfer_encoding: [] + trailer: {} + host: go-auth0-dev.eu.auth0.com + remote_addr: "" + request_uri: "" + body: | + {"client_id":"rZkYzbKzqfoJ9I5jWY0OLlR3jtGGQBQh","audience":"https://api.example.com/","scope":["create:resource"],"allow_any_organization":true,"organization_usage":"allow"} + form: {} + headers: + Content-Type: + - application/json + User-Agent: + - Go-Auth0/latest + url: https://go-auth0-dev.eu.auth0.com/api/v2/client-grants + method: POST + response: + proto: HTTP/2.0 + proto_major: 2 + proto_minor: 0 + transfer_encoding: [] + trailer: {} + content_length: 201 + uncompressed: false + body: '{"id":"cgr_T6Rmz31CTGVHlCmh","client_id":"rZkYzbKzqfoJ9I5jWY0OLlR3jtGGQBQh","audience":"https://api.example.com/","scope":["create:resource"],"organization_usage":"allow","allow_any_organization":true}' + headers: + Content-Type: + - application/json; charset=utf-8 + status: 201 Created + code: 201 + duration: 395.550959ms + - id: 4 + request: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 36 + transfer_encoding: [] + trailer: {} + host: go-auth0-dev.eu.auth0.com + remote_addr: "" + request_uri: "" + body: | + {"grant_id":"cgr_T6Rmz31CTGVHlCmh"} + form: {} + headers: + Content-Type: + - application/json + User-Agent: + - Go-Auth0/latest + url: https://go-auth0-dev.eu.auth0.com/api/v2/organizations/org_kRblHAs7YQpHZNTA/client-grants?include_totals=true&per_page=50 + method: POST + response: + proto: HTTP/2.0 + proto_major: 2 + proto_minor: 0 + transfer_encoding: [] + trailer: {} + content_length: 148 + uncompressed: false + body: '{"grant_id":"cgr_T6Rmz31CTGVHlCmh","client_id":"rZkYzbKzqfoJ9I5jWY0OLlR3jtGGQBQh","audience":"https://api.example.com/","scope":["create:resource"]}' + headers: + Content-Type: + - application/json; charset=utf-8 + status: 201 Created + code: 201 + duration: 418.924083ms + - id: 5 + request: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 5 + transfer_encoding: [] + trailer: {} + host: go-auth0-dev.eu.auth0.com + remote_addr: "" + request_uri: "" + body: | + null + form: {} + headers: + Content-Type: + - application/json + User-Agent: + - Go-Auth0/latest + url: https://go-auth0-dev.eu.auth0.com/api/v2/organizations/org_kRblHAs7YQpHZNTA/client-grants?include_totals=true&per_page=50 + method: GET + response: + proto: HTTP/2.0 + proto_major: 2 + proto_minor: 0 + transfer_encoding: [] + trailer: {} + content_length: -1 + uncompressed: true + body: '{"client_grants":[{"id":"cgr_T6Rmz31CTGVHlCmh","client_id":"rZkYzbKzqfoJ9I5jWY0OLlR3jtGGQBQh","audience":"https://api.example.com/","scope":["create:resource"],"organization_usage":"allow","allow_any_organization":true}],"start":0,"limit":50,"total":1}' + headers: + Content-Type: + - application/json; charset=utf-8 + status: 200 OK + code: 200 + duration: 735.21625ms + - id: 6 + request: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 0 + transfer_encoding: [] + trailer: {} + host: go-auth0-dev.eu.auth0.com + remote_addr: "" + request_uri: "" + body: "" + form: {} + headers: + Content-Type: + - application/json + User-Agent: + - Go-Auth0/latest + url: https://go-auth0-dev.eu.auth0.com/api/v2/organizations/org_kRblHAs7YQpHZNTA/client-grants/cgr_T6Rmz31CTGVHlCmh?include_totals=true&per_page=50 + method: DELETE + response: + proto: HTTP/2.0 + proto_major: 2 + proto_minor: 0 + transfer_encoding: [] + trailer: {} + content_length: 0 + uncompressed: false + body: "" + headers: + Content-Type: + - application/json; charset=utf-8 + status: 204 No Content + code: 204 + duration: 267.537584ms + - id: 7 + request: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 5 + transfer_encoding: [] + trailer: {} + host: go-auth0-dev.eu.auth0.com + remote_addr: "" + request_uri: "" + body: | + null + form: {} + headers: + Content-Type: + - application/json + User-Agent: + - Go-Auth0/latest + url: https://go-auth0-dev.eu.auth0.com/api/v2/organizations/org_kRblHAs7YQpHZNTA/client-grants?include_totals=true&per_page=50 + method: GET + response: + proto: HTTP/2.0 + proto_major: 2 + proto_minor: 0 + transfer_encoding: [] + trailer: {} + content_length: -1 + uncompressed: true + body: '{"client_grants":[],"start":0,"limit":50,"total":0}' + headers: + Content-Type: + - application/json; charset=utf-8 + status: 200 OK + code: 200 + duration: 264.872ms + - id: 8 + request: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 0 + transfer_encoding: [] + trailer: {} + host: go-auth0-dev.eu.auth0.com + remote_addr: "" + request_uri: "" + body: "" + form: {} + headers: + Content-Type: + - application/json + User-Agent: + - Go-Auth0/latest + url: https://go-auth0-dev.eu.auth0.com/api/v2/client-grants/cgr_T6Rmz31CTGVHlCmh + method: DELETE + response: + proto: HTTP/2.0 + proto_major: 2 + proto_minor: 0 + transfer_encoding: [] + trailer: {} + content_length: 0 + uncompressed: false + body: "" + headers: + Content-Type: + - application/json; charset=utf-8 + status: 204 No Content + code: 204 + duration: 323.169708ms + - id: 9 + request: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 0 + transfer_encoding: [] + trailer: {} + host: go-auth0-dev.eu.auth0.com + remote_addr: "" + request_uri: "" + body: "" + form: {} + headers: + Content-Type: + - application/json + User-Agent: + - Go-Auth0/latest + url: https://go-auth0-dev.eu.auth0.com/api/v2/resource-servers/654bb7e9eb2d17b5d2f4909f + method: DELETE + response: + proto: HTTP/2.0 + proto_major: 2 + proto_minor: 0 + transfer_encoding: [] + trailer: {} + content_length: 0 + uncompressed: false + body: "" + headers: + Content-Type: + - application/json; charset=utf-8 + status: 204 No Content + code: 204 + duration: 277.600708ms + - id: 10 + request: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 0 + transfer_encoding: [] + trailer: {} + host: go-auth0-dev.eu.auth0.com + remote_addr: "" + request_uri: "" + body: "" + form: {} + headers: + Content-Type: + - application/json + User-Agent: + - Go-Auth0/latest + url: https://go-auth0-dev.eu.auth0.com/api/v2/clients/rZkYzbKzqfoJ9I5jWY0OLlR3jtGGQBQh + method: DELETE + response: + proto: HTTP/2.0 + proto_major: 2 + proto_minor: 0 + transfer_encoding: [] + trailer: {} + content_length: 0 + uncompressed: false + body: "" + headers: + Content-Type: + - application/json; charset=utf-8 + status: 204 No Content + code: 204 + duration: 482.776666ms + - id: 11 + request: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 0 + transfer_encoding: [] + trailer: {} + host: go-auth0-dev.eu.auth0.com + remote_addr: "" + request_uri: "" + body: "" + form: {} + headers: + Content-Type: + - application/json + User-Agent: + - Go-Auth0/latest + url: https://go-auth0-dev.eu.auth0.com/api/v2/organizations/org_kRblHAs7YQpHZNTA + method: DELETE + response: + proto: HTTP/2.0 + proto_major: 2 + proto_minor: 0 + transfer_encoding: [] + trailer: {} + content_length: 0 + uncompressed: false + body: "" + headers: + Content-Type: + - application/json; charset=utf-8 + status: 204 No Content + code: 204 + duration: 412.182208ms diff --git a/test/data/recordings/authentication/TestLoginWithClientCredentials/Should_support_passing_an_organization.yaml b/test/data/recordings/authentication/TestLoginWithClientCredentials/Should_support_passing_an_organization.yaml new file mode 100644 index 00000000..f4be69d7 --- /dev/null +++ b/test/data/recordings/authentication/TestLoginWithClientCredentials/Should_support_passing_an_organization.yaml @@ -0,0 +1,46 @@ +--- +version: 2 +interactions: + - id: 0 + request: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 201 + transfer_encoding: [] + trailer: {} + host: go-auth0-dev.eu.auth0.com + remote_addr: "" + request_uri: "" + body: audience=my-api&client_id=test-client_id&client_secret=test-client_secret&grant_type=client_credentials&organization=org_test + form: + audience: + - my-api + client_id: + - test-client_id + client_secret: + - test-client_secret + grant_type: + - client_credentials + organization: + - org_test + headers: + Content-Type: + - application/x-www-form-urlencoded + url: https://go-auth0-dev.eu.auth0.com/oauth/token + method: POST + response: + proto: HTTP/2.0 + proto_major: 2 + proto_minor: 0 + transfer_encoding: [] + trailer: {} + content_length: -1 + uncompressed: true + body: '{"access_token":"test-access-token","expires_in":86400,"token_type":"Bearer"}' + headers: + Content-Type: + - application/json + status: 200 OK + code: 200 + duration: 487.449709ms