/admin/users/sync_sso ... Route not found

AI-generated summary

A user is experiencing a “Route Not Found” error when attempting to make a POST request to the /admin/users/sync_sso route. Nopsled initially passes api_username and api_key as form data, but this does not work. Falco suggests passing these as query parameters instead.

Nopsled updates their code to include api_username and api_key as query parameters, but still receives the “Route Not Found” error. supermathie suggests that the api_* parameters should be in the query parameters, not the POST body.

Nopsled understands that the api_username and api_key should be in the query parameters, while the rest of the data is in the POST body. However, blake notes that the api_* parameters can also be in the body.

Another user, shahidmir, is also experiencing the same error when trying to make a POST request via Postman. They try adding the api_username and api_key both in the body and as request parameters but still receive the same error.

shahidmir discovers that regenerating the system API key resolves the issue. th0rgall also experiences the same error and finds that the cause is using a Read Only-scoped API key instead of a Global-scoped key.

Any idea why I’m getting this when trying to issue a POST request?

ActionController::RoutingError (No route matches [POST] “/admin/users/sync_sso”)

Thanks!

Well the route is that one.

Are you passing api_username and api_key as query params too?

I am. Here is the code block. This is the exact say thing I’m doing in my SSO login route. Only difference is obviously the URI.

     const sso = new DiscourseSSO(SSOKey);
            const nonce = 'dummy data';
            const userparams = {
              nonce,
              external_id: user._id.toString(),
              email: user.email,
              username: user.username.replace(/\s/g, ''),
            };
            console.log(userparams);
            const q = sso.buildLoginString(userparams);
            fetch('https://community.testsite.com/admin/users/sync_sso', { method: 'POST', body: q })
              .then(res => res.json())
              .then(json => console.log(json));

You aren’t passing api_username and api_key.

You need those as query params.

You can check our howto in the topic here: Sync DiscourseConnect user data with the sync_sso route

sso.buildLoginString is doing that.

discourse_sso.prototype.buildLoginString = function(params) {
	if(!("external_id" in params)) {
		throw new Exception("Missing required parameter 'external_id'");
	}
	if(!("nonce" in params)) {
		throw new Exception("Missing required parameter 'nonce'");
	}
	if(!("email" in params)) {
		throw new Exception("Missing required parameter 'email'");
	}
	
	var payload = new Buffer( querystring.stringify(params) , 'utf8').toString("base64");
	var hmac = this.getHmac();
	hmac.update(payload);
	
	return querystring.stringify({
		'sso': payload,
		'sig': hmac.digest('hex')
	});

Using this node package for SSO login. Which works perfectly. Trying to repurpose that for this …

https://github.com/ArmedGuy/discourse_sso_node

Where? I don’t see api_username and api_key anywhere.

Right. I was adding in as form data before. Here is the updated. Still getting the Route Not Found error in the rails logs though.

 const userparams = {
          nonce,
          api_username: someusername,
          api_key: somekey,
          external_id: user._id.toString(),
          email: user.email,
          username: user.username.replace(/\s/g, ''),
        };

Code that produces the bottom query:

const userparams = {
      external_id: user._id.toString(),
      email: user.email,
      username: user.username.replace(/\s/g, ''),
    };
    const payload = new Buffer(querystring.stringify(userparams), 'utf8').toString('base64');
    const hmac = crypto.createHmac('sha256', DiscourseSSOKey);
    hmac.update(payload);
    const query = querystring.stringify({
      sso: payload,
      sig: hmac.digest('hex'),
      api_username: UserName,
      api_key: API Key,
    });
    console.log(query);
    fetch('https://community.somesite.com/admin/users/sync_sso', {
      method: 'POST',
      body: query,
    })
      .then(res => res.json())
      .then(json => console.log(json));    

Here’s the query that gets generated and passed as the body on the POST route:

sso=somelongSSOgenerated.&sig=somelongsignature&api_username=someusername&api_key=someAPIKey

This all still gives me a Route Not Found error in the rails logs.

Any thoughts on the above? Does that look right?

You’re delivering the wrong Content-Type. Try providing the object directly as the body to fetch, without querystring.stringify.

also, hang on a sec, i’m going to let you finish, but URLSearchParams is the best browser api of 2016

The api_* parameters need to be in the query parameters, not the POST body.

So you need something like:

fetch('https://community.testsite.com/admin/users/sync_sso?api_username=USERNAME&api_key=KITTENS', { method: 'POST', body: body })

Ah understood. So the api_username and api_key in the query parameters and the rest in the post body.

They can also be in the body

All my Postman requests have them in the body:

Unless this route is special?

It’s not. The WordPress plugin sends the api parameters for the sync_sso route in the body of the request: wp-discourse/lib/sso-provider/discourse-sso.php at main · discourse/wp-discourse · GitHub

That’s correct, the problem was sending the wrong body type so the api_username/api_key couldn’t be parsed out.

Hi

I am attemping the SSO sync but getting the no route found error. Im trying via postman.
I have tried adding the key and username both in the body and as request params, but same result.

any ideas?

hi,
could you elaborate on this… if using postman, what headers/values need to be set?

The Content-Type should be “multipart/form-data”, but I don’t think you have to set that in the header if the Body is already set to “form-data” (my Headers in Postman are all blank).

hmmm, theres not much in the logs to highlight where the issue is…
failing that, is it most likely the payload and sig thats the problem?

For testing this, im doing the following:

  1. taking the following payload string:
    email=discourse-sso2@gmail.com&external_id=auth0|111111111111233444&require_activation=false

  2. Generating the base64 encoded payload via:
    https://www.base64encode.org/

  3. Taking that payload and generating the hmac-Sha256 encryped payload via:
    Free Online HMAC Generator / Checker Tool (MD5, SHA-256, SHA-512) - FreeFormatter.com

  4. Then sticking them both in postman, sso=payload, sig=encrypted payload

  5. I have generated an API key for user ‘system’ and passing that in with the body.

Error i get in discourse logs:

Started POST “/discussion/admin/users/sync_sso” for 123.157.28.69 at 2018-05-24 15:45:08 +0000

ActionController::RoutingError (No route matches [POST] “/admin/users/sync_sso”)

/var/www/discourse/vendor/bundle/ruby/2.4.0/gems/actionpack-5.1.4/lib/action_dispatch/middleware/debug_exceptions.rb:63:in `call’

Rendering text template