Getusertoken.sh doesn't work in new service extension, with same values as working one

Hi folks,

We have a second service extension based on our (working) first one. I decided to re-use the client ID and secret from the first service extension, and set up the app that way on the portal. (This may be the problem but it’s not clear why.)

In the first, working service extension, I use getusertoken.sh with my AB user/pass and get a bearer token to use when testing grpc calls in Postman. This works reliably.

With the new service extension, I’ve set up the .env file (from which I get the necessary env vars) with the exact same values as in the working one. I’ve confirmed they match the service extension app values (id, secret, base url).

However, the script just exits immediately with no output. I threw in a few echo statements and found that the REQUEST_ID curl call is failing with an HTTP 302 (redirect) to the AB login screen:

REQUEST_ID="$(curl -s -D - "${AB_BASE_URL}/iam/v3/oauth/authorize?response_type=code&code_challenge_method=S256&code_challenge=$(get_code_challenge "$CODE_VERIFIER")&client_id=$AB_CLIENT_ID" | grep -o 'request_id=[a-f0-9]\+' | cut -d= -f2)"

HTTP/2 302 
date: Tue, 16 Jul 2024 07:26:38 GMT
content-length: 0
location: https://prod.gamingservices.accelbyte.io/auth/?client_id=09cf8628de2442448693cda448cb601c&is_one_time_link_code_flow=false&redirect_uri=https%3A%2F%2Fstudio.dev.gamingservices.accelbyte.io&request_id=75e96a38029e485da8d7c0001c0334f8
cache-control: no-cache, no-store, max-age=0, must-revalidate
expires: Fri, 01 Jan 1990 00:00:00 GMT
pragma: no-cache
x-ab-traceid: d4147b59af8449718c4206892f20aa23
x-envoy-upstream-service-time: 9
server: envoy

I’ve checked everything I can think of and I’m out of ideas. I won’t be able to test the new service extension locally until I figure it out.

Any suggestions?

Thanks,
Chris

Hello Chris, I’m Eric Chan from Extend.

That IAM authorize call emitting http 302 redirect is normal. In your script (don’t have to copy&paste to the forum), but could you echo out the required AB_CLIENT_ID, AB_CLIENT_SECRET, AB_BASE_URL and check yourself making sure they are indeed correct within that very bash environment?

For the first (working) vs the second (non-working) apps, just quickly checking, the .env files are they exactly the same, including the BASE_PATH, or has the BASE_PATH been manually edited based on what’s shown on the Admin Portal of the apps?

In addition, could you also echo out $CODE_DATA, $CODE, and add some echo in between those IAM calls (again keep them yourselves don’t attach to the forum here, but check to see if they look legit)? We’d like to pinpoint which later IAM calls actually failed.

Side:

  • I assume you are using getusertoken.sh to test out the auth feature and locally enabling PLUGIN_GRPC_SERVER_AUTH_ENABLED to true already?
  • on the other hand, if you are not testing gRPC auth, to unblock you feel free to set PLUGIN_GRPC_SERVER_AUTH_ENABLED=false therefore can bypass to not need to call getusertoken.sh

Update: @dhanarab is preparing a new script to help to debug this

Hi @ericchan,

Thanks for getting back to me and sorry for the delay replying (I have a day job). The BASE_PATH values in both the working and failing .env files are different, exactly what their respective AB apps say each should be. The working one works, the failing one fails.

Neither command gets as far as CODE_DATA or CODE. That’s why I had to debug further up. The REQUEST_ID assignment curl line is the one that fails with a 302.

Thanks,
Chris

Again, I’m a bit worried that sharing an IAM user between service extensions isn’t supported. If it isn’t, that would likely be the problem. It’s not clear that it wasn’t, so I went ahead and shared them for consistency and maintenance sake. I haven’t seen any best practice guidelines for this.

Hi @chrislambertus ,
The team will take a look soon.

For the IAM client topic, technically you can share your IAM client with multiple Extend apps or other software. However I don’t recommend this.The reason is to reduce the impact if your IAM client ID and secret leaked.

1 Like

Hi @chrislambertus

To better understand the issue you are facing, could you try to use the attached getusertoken-d1.sh to get the user token and post the output?

You can use it the same way as getusertoken.sh but it will print out more useful information.

Additionally, we can try to compare the output of getusertoken-d1.sh between the old working one and the new one.

getusertoken-d1.txt (2.3 KB)

If everything is normal, the output will look similar to this.

ubuntu2204@Dhanar-AB:/mnt/d/git/extend-service-extension-csharp$ bash getusertoken-d1.sh "$AB_USERNAME" "$AB_PASSWORD"

DEBUG AUTHORIZE:
HTTP/2 302 
date: Wed, 17 Jul 2024 07:24:03 GMT
content-length: 0
location: https://stage.accelbyte.io/auth/?client_id=0b9d6bc44901495aa84163fc93bed0b0&is_one_time_link_code_flow=false&redirect_uri=http%3A%2F%2F127.0.0.1&request_id=72427248d5eb400f9a08099d9c399540
cache-control: no-cache, no-store, max-age=0, must-revalidate
expires: Fri, 01 Jan 1990 00:00:00 GMT
pragma: no-cache
x-ab-traceid: f2400be4617a48fb8327c2e1a286c01a
x-envoy-upstream-service-time: 6
server: envoy


DEBUG AUTHENTICATE:
HTTP/2 302 
date: Wed, 17 Jul 2024 07:24:04 GMT
content-length: 0
location: http://127.0.0.1?code=0f59fea611824bde943ee712375c3c64&state=
cache-control: no-cache, no-store, max-age=0, must-revalidate
expires: Fri, 01 Jan 1990 00:00:00 GMT
pragma: no-cache
set-cookie: auth-trust-id=f4f7b13850744cba908f84c2680b0133; Path=/; Expires=Fri, 16 Aug 2024 07:24:04 GMT; HttpOnly; Secure; SameSite=None
x-ab-traceid: 7614dfb8ec6b4363b1bddb9670396d86
x-envoy-upstream-service-time: 28
server: envoy

eyJhbGciOiJSUzI1NiIsImtpZCI6IjBmOWQwMTIyOTE3MjQxM2Q5ODNjYzdmMjhhODZiZWQ5N...

Thanks,

Dhanar

PS. Please rename getusertoken-d1.txt to getusertoken-d1.sh before trying it out.

Hi,

I downloaded the new script you linked and renamed it to getusertoken-d1.sh. I added a line at the top to set the appropriate env vars from my .env file:

set -o allexport && source .env && set +o allexport

When I ran the script, it did the same thing as the other one: no output, immediate exit.

Any ideas?

Thanks,
Chris

Correction: your script also output two new files:

api_curl_http_code.out
api_curl_http_header.out

The “header” file is empty. The “code” file contains this:

000

Hi @chrislambertus,

Can you try to set environment variable different way?

I tried adding set -o allexport && source ../extend-sdk-test-starter.env && set +o allexport as you said and yes the script exits without any output.

Our suggestion is to set the required environment variable using the method mentioned in the README.

export AB_BASE_URL='http://test.accelbyte.io'    # Your environment's domain Base URL
export AB_CLIENT_ID='xxxxxxxxxx'                 # Client ID from the Prerequisites section
export AB_CLIENT_SECRET='xxxxxxxxxx'             # Client Secret from the Prerequisites section

Thanks!

Regards,

Dhanar

When I call the same line outside the script, I get the same result (as expected).

$ ./getusertoken-d1.sh username@domain.com ***password***
AB_CLIENT_ID is not set
$ set -o allexport && source .env && set +o allexport
$ ./getusertoken-d1.sh username@domain.com ***password***
$ echo $AB_CLIENT_ID
09***1c

When I use your method of setting environment variables, I do get output:

$ export AB_CLIENT_ID='09***1c'
$ export AB_CLIENT_SECRET='***'
$ export AB_BASE_URL='https://namespace.prod.gamingservices.accelbyte.io'
$ ./getusertoken-d1.sh **user** **pass**

DEBUG AUTHORIZE:
HTTP/2 302
date: Thu, 18 Jul 2024 04:12:42 GMT
content-length: 0
location: https://prod.gamingservices.accelbyte.io/auth/?client_id=09cf8628de2442448693cda448cb601c&is_one_time_link_code_flow=false&redirect_uri=http%3A%2F%2F127.0.0.1&request_id=c11bb64ec65246408823cd1f3be58953
cache-control: no-cache, no-store, max-age=0, must-revalidate
expires: Fri, 01 Jan 1990 00:00:00 GMT
pragma: no-cache
x-ab-traceid: c3e6f1dd9e844e459dfedf78326845b5
x-envoy-upstream-service-time: 10
server: envoy


DEBUG AUTHENTICATE:
HTTP/2 302
date: Thu, 18 Jul 2024 04:12:43 GMT
content-length: 0
location: https://prod.gamingservices.accelbyte.io/auth/?error=invalid_request&error_description=invalid+authentication+parameters%3A+username+is+empty&error_uri=
cache-control: no-cache, no-store, max-age=0, must-revalidate
expires: Fri, 01 Jan 1990 00:00:00 GMT
pragma: no-cache
x-ab-traceid: f0a3a2dd849548f6b824c42afbdd4202
x-envoy-upstream-service-time: 3
server: envoy

So my question would be: why does my set technique work for one service extension and not for the other? Is it that my other service extension is somehow older, even though it was rebuilt on top of the latest guildservice sample and the app was recreated and this new one was a derivative of that?

Also, my actual use for this is to test in Postman with this bearer token. I briefly looked into converting this script into a Postman script to create a bearer token for each run, but it looked far too difficult to be worth the time. Is there a version of this that could work for that use case?

I think a lot of developers might code up a service extension, debug it in VS Code by hitting F5 with an appropriate launch configuration, and then using Postman to connect to and interact with their extension. It seems like this would be a good case to support directly.

Thanks,
Chris

Hi @chrislambertus,

Since there are multiple questions here, let’s discuss it one by one.

1. When using method of setting env var in README - location: https://prod.gamingservices.accelbyte.io/auth/?error=invalid_request&error_description=invalid+authentication+parameters%3A+username+is+empty&error_uri=

Things that we can try:

  1. Are we forgetting to specify username when executing getusertoken-d1.sh?
  2. Is username and/or password contains characters that needs to be percent encoded?
  3. Uncomment set -x in getusertoken-d1.sh and run it again. It will print all commands executed by the shell script. IMPORTANT: Make sure to redact the client secret and password before sharing the output.

2. About - set -o allexport …

Why set -o allexport && source ../.env && set +o allexport does not work, I guess this question is about general bash shell scripting. I am guessing the intention is to load variables that’s written in .env file to the current shell. But yeah it does not work in this case and personally I have never used that method. I wonder where you found this method.

3. Is it that my other service extension is somehow older, even though it was rebuilt on top of the latest guildservice sample and the app was recreated and this new one was a derivative of that?

Well if you are asking about getusertoken.sh, it is an independent script that can help to get you user access token for various purposes. It does not depend on the rest of extend service extension project.

4. About getting user token using postman

Let me take a look at that whether it is possible.

Thanks.

Regards,

Dhanar

Hi @chrislambertus,

Here is the postman collection for login user which is equivalent to getusertoken.sh.

Import it to your Postman, create an environment with the required variables, and run the collection.

If successful, it will look something like this.

Please have a look later.

Thanks.

Regards,

Dhanar

PS. Rename ags-login-user.postman_collection.txt to ags-login-user.postman_collection.json before importing to Postman.

ags-login-user.postman_collection.txt (5.8 KB)

2 Likes

Awesome, that works! Thanks, I’m sure folks will find it very helpful.

Cheers,
Chris

2 Likes

For others who come here, there’s an extra bit of automation you can do.

The above JSON creates an ags-login-user collection. I set the following as a post-run script on that collection:

pm.environment.set("auth", pm.cookies.get('access_token'));

This retrieves the access token returned from the call and sets an environment variable named auth. You will probably have to create that variable before running.

I can use this variable in my gRPC requests by setting the Bearer token in Authorization on my grpc calls to {{auth}}. Then whenever I need to refresh the token, I just run the ags-login-user collection, it does its magic, and the I can run my requests straight away.

2 Likes