Troubleshooting OAuth 2.0 Connections
This pages focuses on troubleshooting OAuth 2.0 authorization code connections, but similar debugging concepts can be applied to client credentials connections. Note that every application implements OAuth 2.0 a little differently, but this provides general recommendations for debugging OAuth 2.0 connections.
Troubleshooting authorization endpoints
When a customer user clicks Connect, they are brought to a third-party app's Authorization URL. Your client ID, the config variable's ID, permission scopes and the redirect URI is appended as search parameters to the Authorize URL.
For example, if the external application's authorize URL is https://auth.example.com/authorize
, and your client ID is abc-123
, your user will be directed to
https://auth.example.com/authorize?client_id=abc-123&redirect_uri=https%3A%2F%2Foauth2.prismatic.io%2Fcallback&scope=widget%3Aread+widget%3Awrite&state=SW5example
Here, state
represents the config variable's ID in Prismatic, and is used when the user returns to our callback URL to determine which config variable to update.
Invalid client_id errors
If your users arrive at an authorization page that says "Invalid client_id parameter" (or a similar error), you should double-check your client ID. Verify that there are no leading or trailing whitespace characters, and that the client ID matches the client ID that you saw when you configured your application in the third-party system.
Incorrect redirect_uri errors
If your customers see an authorization page that says "redirect_uri mismatch" (or a similar error), you should verify that the callback URL you configured in the third-party system is correct.
For the US region, the callback URL is https://oauth2.prismatic.io/callback
.
For other public regions, private cloud hosted options, or white-labeled callback URLs, see Authorization code callback URL.
Troubleshooting code token exchange
After authenticating with a third-party app and walking through the app's consent screen, a user will return to Prismatic's OAuth 2.0 callback URL with their authorization code in hand. Depending on if you white-label the callback URL or if you're hosted in a different region, they'll end up on a URL that looks similar to:
https://oauth2.prismatic.io/callback?code=some-unique-auth-code&state=SW5example
The Prismatic OAuth 2.0 service then loads the config variable from the state
parameter to match a config variable's ID, and attempts to exchange the code
for an access_token
using the third party app's token URL.
Flavors of auth code token exchange
Different apps implement auth code exchange in different ways. Some apps expect you to pass your client ID and secret as a base64-encoded auth header. Others expect that they're passed in a body. Some apps expect that your body is formdata-encoded, while others expect JSON.
The Prismatic OAuth 2.0 service attempts each of the six common "flavors" of auth code token exchange, in order of popularity, and succeeds once one has succeeded, and fails if none succeed.
Suppose your client ID is my-client-id
, your client secret is my-client-secret
, and the code
your customer returned with is some-unique-auth-code
.
Prismatic would attempt these token exchanges:
-
Client ID / secret are URL-encoded and then base64-encoded and sent as an auth header. Body is formdata-encoded
curl -X POST \
--header 'Authorization: Basic bXktY2xpZW50LWlkOm15LWNsaWVudC1zZWNyZXQ=' \
--header 'Content-Type: application/x-www-form-urlencoded' \
https://app.example.com/oauth2/token \
--data 'grant_type=authorization_code&scope=widgets%3Aread%20widgets%3Awrite%20offline_access&redirect_uri=https%3A%2F%2Foauth2.prismatic.io%2Fcallback&code=some-unique-auth-code' -
Client ID / secret are URL-encoded and then base64-encoded and sent as an auth header. Body is JSON-encoded
curl -X POST \
--header 'Authorization: Basic bXktY2xpZW50LWlkOm15LWNsaWVudC1zZWNyZXQ=' \
--header 'Content-Type: application/json' \
https://app.example.com/oauth2/token \
--data '{"code":"some-unique-auth-code","grant_type":"authorization_code","redirect_uri":"https://oauth2.prismatic.io/callback","scope":"widgets:read widgets:write offline_access"}' -
Client ID / secret are sent within the body. Body is formdata-encoded
curl -X POST \
--header 'Content-Type: application/x-www-form-urlencoded' \
https://app.example.com/oauth2/token \
--data 'grant_type=authorization_code&scope=widgets%3Aread%20widgets%3Awrite%20offline_access&redirect_uri=https%3A%2F%2Foauth2.prismatic.io%2Fcallback&code=some-unique-auth-code&client_id=my-client-id&client_secret=my-client-secret' -
Client ID / secret are sent within the body. Body is JSON-encoded
curl -X POST \
--header 'Content-Type: application/json' \
https://app.example.com/oauth2/token \
--data '{"client_id":"my-client-id","client_secret":"my-client-secret","code":"some-unique-auth-code","grant_type":"authorization_code","redirect_uri":"https://oauth2.prismatic.io/callback","scope":"widgets:read widgets:write offline_access"}' -
Client ID / secret are just base64-encoded and sent as an auth header. Body is formdata-encoded. This will be the same as flavor #1, but characters (like whitespace) are not URL-encoded before base64-encoded.
-
Client ID / secret are just base64-encoded and sent as an auth header. Body is JSON-encoded. This will be the same as flavor #2, but characters (like whitespace) are not URL-encoded before base64-encoded.
Mocking a token exchange endpoint
If you'd like to see exactly what the Prismatic OAuth 2.0 service attempts to send a token endpoint, you can spin up a Docker container locally to simulate a token endpoint.
Run a Smocker container:
docker run -d --restart=always \
-p 8080:8080 \
-p 8081:8081 \
--name smocker \
thiht/smocker
Then, declare a token "smock" endpoint:
curl -XPOST \
localhost:8081/mocks \
--header "Content-Type: application/x-yaml" \
--data \
'
- request:
method: POST
path: /oauth2/token
response:
status: 200
headers:
Content-Type: application/json
body: >
{
"access_token": "my-access-token",
"token_type": "bearer",
"expires_in": 60,
"example_parameter": "example_value",
"refresh_token": "my-refresh-token"
}
'
This endpoint will accept any request, and return a fake access token response.
Next, expose your Docker container with ngrok:
ngrok http 8080
From there, you can take note of your ngrok
endpoint and set your Token URL in your connection to something like https://31ce-123-123-123-123.ngrok-free.app/oauth/token
.
By visiting http://localhost:8081
, you'll be able to view each request Prismatic's OAuth 2.0 service made.
If you change the status
in the smock to status: 500
, you'll see all six token exchange requests that Prismatic's OAuth 2.0 token exchange service made.
Verify token exchange works with Postman
Once you've captured a token request, try to send that equivalent request to your third-party app either with curl
or Postman.
If you get a 404, you may have the wrong token URL configured.
You may also get a more descriptive response which can help you identify changes you need to make to scopes, etc.
Tokens refresh errors
If a token exchange works initially, but later the token fails to refresh, it's possible that you omitted an offline_access scope, which many apps use to indicate that you need long-term access.