Go API custom domain returns error: bad audience

Following the Auth0 Go SDK Quickstart, I have successfully integrated Auth0 login token exchange with my Go API fronted by a VueJs web interface. I’m at the point that I want to use custom domain for the universal login workflow.

My custom domain is configured, and returns a successful test, in Auth0 management console for my tenant. I have modified the environment settings to utilize to change from the default Auth0 tenant URI to my custom domain values:

web/.env

...
VITE_AUTH0_DOMAIN=auth.my-domain.com
...

api/src/.env

# The URL of our Auth0 Tenant Domain.
AUTH0_TENANT='dev-my-tenant.us.auth0.com'

# If you're using a Custom Domain, be sure to set this to that value instead.
# AUTH0_DOMAIN='dev-my-tenant.us.auth0.com'
AUTH0_DOMAIN='auth.my-domain.com'

# Our Auth0 API's Identifier.
# https://auth0.com/docs/customize/custom-domains/configure-features-to-use-custom-domains#apis
AUTH0_AUDIENCE='https://dev-api.my-domain.com/'
...

I’m using the following code for retrieving the Auth0 API token:

	payload := strings.NewReader("{\"client_id\":\"my-machine-to-machine-client-id\",\"client_secret\":\"my-client-secret\",\"audience\":\"" + auth0Audience + "\",\"grant_type\":\"client_credentials\"}")

	fmt.Print(".")
	req, _ := http.NewRequest("POST", url, payload)

	req.Header.Add("content-type", "application/json")

	fmt.Print(".")
	res, _ := http.DefaultClient.Do(req)
	fmt.Print(".")

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)
	fmt.Print(".")

	var dat map[string]interface{}
	err := json.Unmarshal(body, &dat)
	if err != nil {
		log.Println("[ERROR] Unable to unmarshal auth0 api token response body. Here's why: ", err)
	}
	fmt.Print(".")

	log.Printf("[DEBUG] Auth0 API token response body: %s", string(body))

	if res.StatusCode != http.StatusOK {
		log.Println("[ERROR] Unable to get Auth0 API token. Here's why: ", dat)
		return
	}

	auth0ApiToken = dat["access_token"].(string)
	fmt.Println(". Done!")
}

From the debugging output, I can enter the access_token returned into jwt.io and verify the "aud": "https://dev-api.my-domain.com/", returns what I am expecting and as configured in Auth0 tenant default audience value.

When I go to call the API using the access_token, such as the following functoin:

func GetAuth0PermissionsByUserId(userid string) ([]Auth0UserPermission, error) {
	userid = strings.Replace(userid, "|", "%7C",-1)
	url := "https://" + auth0Domain + "/api/v2/users/" + userid + "/permissions"
	log.Printf("[DEBUG] Auth0 user permissions URL: %s", url)
	req, _ := http.NewRequest("GET", url, nil)
	req.Header.Add("content-type", "application/json")
	req.Header.Add("authorization", "Bearer " + auth0ApiToken)
	log.Printf("[DEBUG] Auth0 user permissions headers: %v", req.Header)
	res, err := http.DefaultClient.Do(req)

	if err != nil {
		log.Printf("[ERROR] Unable to get Auth0 user permissions. Here's why: %v\n", err)
	}

	defer res.Body.Close()
	body, err := io.ReadAll(res.Body)
	if err != nil {
		log.Printf("[ERROR] Unable to read response body. Here's why: %v\n", err)
		return nil, err
	}
...
}

I continue to receive the following response:

[DEBUG] Auth0 user permissions response body: {"statusCode":401,"error":"Unauthorized","message":"Bad audience: https://dev-api.my-domain.com/"}

I’m at a loss for additional configuration or code changes to attempt to make my custom domain work with my API. The login flow works as expected from my front end, but I’m struggling to find the silver bullet in the Auth0 docs and other general research I’ve performed.

Hi @gantta,

Welcome to the Auth0 Community!

I understand you are getting a “Bad audience” error. I found this solution that may prove helpful: 401 - Bad Audience - #3 by rueben.tiow

Another Community post: Bad Audience Error

Please let me know your thoughts after reviewing the above!

Best,

Mary Beth

1 Like

Thanks for pointing me in that direction. After reviewing the suggestions in the post, I ended up with the following for my Go API .env file:

# The URL of our Auth0 Tenant Domain.
AUTH0_TENANT='dev-my-auth-domain.us.auth0.com'

# If you're using a Custom Domain, be sure to set this to that value instead.
AUTH0_DOMAIN='auth.my-custom-domain.com'

# Our Auth0 API's Identifier.
AUTH0_AUDIENCE='https://dev-my-auth0-domain.us.auth0.com/api/v2/'
TOKEN_AUDIENCE='https://dev-api.my-custom-domain.com/'
...

Deviating from the quickstart sample, I added the TOKEN_AUDIENCE and use that value in the EnsureValidToken() function,:

func EnsureValidToken() func(next http.Handler) http.Handler {
	issuerURL, err := url.Parse("https://" + os.Getenv("AUTH0_DOMAIN") + "/")
	if err != nil {
		log.Fatalf("[ERROR] Failed to parse the issuer url: %v", err)
	}

	provider := jwks.NewCachingProvider(issuerURL, 5*time.Minute)

	jwtValidator, err := validator.New(
		provider.KeyFunc,
		validator.RS256,
		issuerURL.String(),
		[]string{os.Getenv("TOKEN_AUDIENCE")},
		validator.WithCustomClaims(
			func() validator.CustomClaims {
				return &CustomClaims{}
			},
		),
		validator.WithAllowedClockSkew(30 * time.Minute), // Increase the allowed clock skew
	)
...

The reason I made those changes was after interrogating the returned aud from the tokens during the various jwt exchanges, I was able to match the expected audience values and successfully authenticate protected endpoints in my API utilizing my custom auth domain.

Thanks for the help.

1 Like