get_token and acurl is not working in Windows 10 with Git Bash/Cygwin terminals

Hi,

My organization has Apigee SaaS with single sign on enabled. For using the management API using single sign on, I wanted to generate the bearer token as suggested in the link.

https://docs.apigee.com/api-platform/system-administration/auth-tools

Issue:

1. I followed the steps as suggested in the resource link and installed sso.cli utility in my machine.

2. I executed get_token and acurl utilities with passcode. I see that sso.cli folder created in the executed location but there is no token generated. No error on the terminal as well.

Could you suggest where is the gap and how to resolve this issue?

Solved Solved
2 9 1,455
1 ACCEPTED SOLUTION

That's lame.

I haven't tried those tools directly. I don't know what the problem might be.

Are you committed to using Bash/Cygwin? If not, here are some things that might help.


The get_token thing is not magic. It's just a wrapper around the API. You could construct the same, yourself, in a simple Powershell module.

You said

My organization has Apigee SaaS with single sign on enabled.

OK, that means you have a zone name. Here's what you should do.

  1. Using your browser, login to apigee, with your zone login. This will be https://ZONENAME.login.apigee.com/
  2. You will need to authenticate according to the requirements of your IDP. Maybe it will be as simple as username + password. Maybe it will be username, password, and a One-time-password or authenticator code. Or maybe some other combination. Anyway, you know what this is. A normal Authentication motion form your IdP.
  3. Now, using the same browser, in a new tab visit https://ZONENAME.login.apigee.com/passcode

    This will display a one-time code in your browser.

    The /passcode endpoint looks at the authenticated browser session, and if it is valid, generates that code.

  4. With a script, POST to https://ZONENAME.login.apigee.com/oauth/token with these params

    headers:

    Content-Type: 'application/x-www-form-urlencoded',
    Authorization: 'Basic ZWRnZWNsaTplZGdlY2xpc2VjcmV0'
    	

    body:

    grant_type=password&response_type=token&passcode=ONE_TIME_CODE
    	

    The Authorization header is always the same. It represents the client id and client secret (not really a secret). This is the same id + secret pair used by get_token. It's just an identity for the administrative program. Really Apigee should allow additional sets of these, but for now there is just one.

    The payload is always form-urlencoded. Replace the ONE_TIME_CODE with the thing you got in the previous browser page, the passcode.

    The result will be a JSON payload like this:

    {
        "access_token": "***",
        "token_type": "bearer",
        "refresh_token": "***",
        "expires_in": 43199,
        "scope": "scim.emails.read scim.me openid password.write approvals.me scim.ids.read oauth.approvals",
        "jti": "414a7982-da48-45a7-af66-f562dd553a9c"
    }
    

The access_token you receive in that response is the thing you need to embed into future Admin API calls, as a bearer token. In my case the token is good for 44000 seconds, which is just over 12 hours. Your situation may be different.

You can of course cache that token and re-use it as you wish, up til the expiry time.

After the token has expired, you can get a new token using the refresh_token. The request for that again is a POST to https://ZONENAME.login.apigee.com/oauth/token, and the headers are the same as described above. The body should be as above, form-urlencoded, but with different contents, like this:

refresh_token=REFRESH_TOKEN_HERE&grant_type=refresh_token

Notice you do not need a passcode for this refresh_token request. In response to this, you will get the same access_token payload I described above.

I don't know the lifetime of the refresh token. The access_token might expire in 12 hours, or maybe it's different for your zone, but in any case the access_token response tells you the expiry of the access_token itself. After the access_token expires you can use the refresh token request I just described to get a new access_token (and a new refresh token). But the refresh token also expires, though the payload doesn't tell you when it expires. I believe the lifetime might be 24 hours. It is not documented, as far as I know.

If the refresh token has expired, you will get a 401 from the request I just described, and that means you need to start at step 1 above, and use the passcode.

It doesn't hurt to just periodically refresh the token, every once in a while, and then stash the new token. Then you would always have a token available, and you don't need to continually visit the /passcode endpoint in your browser to get that passcode.

View solution in original post

9 REPLIES 9

That's lame.

I haven't tried those tools directly. I don't know what the problem might be.

Are you committed to using Bash/Cygwin? If not, here are some things that might help.


The get_token thing is not magic. It's just a wrapper around the API. You could construct the same, yourself, in a simple Powershell module.

You said

My organization has Apigee SaaS with single sign on enabled.

OK, that means you have a zone name. Here's what you should do.

  1. Using your browser, login to apigee, with your zone login. This will be https://ZONENAME.login.apigee.com/
  2. You will need to authenticate according to the requirements of your IDP. Maybe it will be as simple as username + password. Maybe it will be username, password, and a One-time-password or authenticator code. Or maybe some other combination. Anyway, you know what this is. A normal Authentication motion form your IdP.
  3. Now, using the same browser, in a new tab visit https://ZONENAME.login.apigee.com/passcode

    This will display a one-time code in your browser.

    The /passcode endpoint looks at the authenticated browser session, and if it is valid, generates that code.

  4. With a script, POST to https://ZONENAME.login.apigee.com/oauth/token with these params

    headers:

    Content-Type: 'application/x-www-form-urlencoded',
    Authorization: 'Basic ZWRnZWNsaTplZGdlY2xpc2VjcmV0'
    	

    body:

    grant_type=password&response_type=token&passcode=ONE_TIME_CODE
    	

    The Authorization header is always the same. It represents the client id and client secret (not really a secret). This is the same id + secret pair used by get_token. It's just an identity for the administrative program. Really Apigee should allow additional sets of these, but for now there is just one.

    The payload is always form-urlencoded. Replace the ONE_TIME_CODE with the thing you got in the previous browser page, the passcode.

    The result will be a JSON payload like this:

    {
        "access_token": "***",
        "token_type": "bearer",
        "refresh_token": "***",
        "expires_in": 43199,
        "scope": "scim.emails.read scim.me openid password.write approvals.me scim.ids.read oauth.approvals",
        "jti": "414a7982-da48-45a7-af66-f562dd553a9c"
    }
    

The access_token you receive in that response is the thing you need to embed into future Admin API calls, as a bearer token. In my case the token is good for 44000 seconds, which is just over 12 hours. Your situation may be different.

You can of course cache that token and re-use it as you wish, up til the expiry time.

After the token has expired, you can get a new token using the refresh_token. The request for that again is a POST to https://ZONENAME.login.apigee.com/oauth/token, and the headers are the same as described above. The body should be as above, form-urlencoded, but with different contents, like this:

refresh_token=REFRESH_TOKEN_HERE&grant_type=refresh_token

Notice you do not need a passcode for this refresh_token request. In response to this, you will get the same access_token payload I described above.

I don't know the lifetime of the refresh token. The access_token might expire in 12 hours, or maybe it's different for your zone, but in any case the access_token response tells you the expiry of the access_token itself. After the access_token expires you can use the refresh token request I just described to get a new access_token (and a new refresh token). But the refresh token also expires, though the payload doesn't tell you when it expires. I believe the lifetime might be 24 hours. It is not documented, as far as I know.

If the refresh token has expired, you will get a 401 from the request I just described, and that means you need to start at step 1 above, and use the passcode.

It doesn't hurt to just periodically refresh the token, every once in a while, and then stash the new token. Then you would always have a token available, and you don't need to continually visit the /passcode endpoint in your browser to get that passcode.

HI @Dino-at-Google,

Thank you for detailed response. I tried the way you suggested in postman and getting bad credentials error. token url https://ZONENAME.login.apigee.com/oauth/token

Same settings tried in my trial account(https://login.apigee.com/oauth/token)but the result same. attached image for reference.

Question: Auth header should be the email address and password which used to login the edge right?

capture.png

Hi Dino,

It started working when I pass user name and password instead of passcode in the body parameters. Rest of the settings are same as you mentioned. Thanks!

capture.png

Hmmmm! Well that's interesting,. Maybe your IdP does not require multi-factor authentication, and that;s why you need to use the password grant.

In any case I'm glad you figured it out!

Hi,

I followed all the steps but getting "bad Credentials" error, just trying to understand Basic Authorization value consists of base64encoding(edge ui username:password)? or is there nay separate client id an client secret need to use? if yes, where I can find client id an dclient secret?

Thanks

Venkat

No.

The Basic Authorization header is a fixed value. It is the base64 encoding of a known clientid:secret. You should use what I showed in step 4 above for that header.

If you are using password grant, the user credentials go in the post body as form params.

like this:

grant_type=password&response_type=token&password={password}&username={username}

Thanks Dino.

When I try that header value and username, password in the payload then I am getting below error, no clue what is this usergrid?

{ "error": "unauthorized", "error_description": "Unable to find identity provider for origin:usergrid" }

ok that's odd. I infer from that message that something is strange with your identity provider.

Do you have an identity Zone provisioned? (in other words, are you using SAML?) If so, you need to use the passcode approach.

If not you can use the direct username+password approach.

This is documented here.

Hi @Venkateshwar ,

I'm testing the SAML SSO in ApiGee and i'm getting the same error on sending request for get token:

{ "error": "unauthorized", "error_description": "Unable to find identity provider for origin:usergrid" }

Were you able to solve this issue?