TheThingsNetwork / lorawan-stack

The Things Stack, an Open Source LoRaWAN Network Server
https://www.thethingsindustries.com/stack/
Apache License 2.0
976 stars 307 forks source link

Can't exchange authorization code for an OAuth access token #6518

Open romach opened 1 year ago

romach commented 1 year ago

Summary

I get 400 error when I try to exchange authorization code for an OAuth access token according to the documentation https://www.thethingsindustries.com/docs/reference/api/authentication/

Response body:

{
    "code": 3,
    "message": "error:pkg/oauth:invalid_request (invalid or missing request parameter)",
    "details": [
        {
            "@type": "type.googleapis.com/ttn.lorawan.v3.ErrorDetails",
            "namespace": "pkg/oauth",
            "name": "invalid_request",
            "message_format": "invalid or missing request parameter",
            "correlation_id": "f58fe39f7984450a969c2134bac2835c",
            "code": 3
        }
    ]
}

Steps to Reproduce

  1. Get authorization code with request https://eu1.cloud.thethings.network/oauth/authorize?client_id=<oauth_client_id>&redirect_uri=<redirect_uri>&response_type=code
  2. Exchange authorization code for an OAuth access token using request
POST /oauth/token HTTP/1.1
Host: eu1.cloud.thethings.network
Content-Type: application/json
Authorization: Basic <AUTHORIZATION_HEADER>
Content-Length: 156

{
    "grant_type": "authorization_code",
    "code": "<AUTHORIZATION_CODE>"
}

Current Result

Error with code 400 and body:

{
    "code": 3,
    "message": "error:pkg/oauth:invalid_request (invalid or missing request parameter)",
    "details": [
        {
            "@type": "type.googleapis.com/ttn.lorawan.v3.ErrorDetails",
            "namespace": "pkg/oauth",
            "name": "invalid_request",
            "message_format": "invalid or missing request parameter",
            "correlation_id": "f58fe39f7984450a969c2134bac2835c",
            "code": 3
        }
    ]
}

Expected Result

Response with status code 200 and body

{
  "access_token": "XXXXX", 
  "token_type": "bearer", 
  "expires_in": "3600",
  "refresh_token": "YYYYY"
}

Relevant Logs

No response

URL

https://eu1.cloud.thethings.network/oauth/token

Deployment

The Things Stack Community Edition

The Things Stack Version

No response

Client Name and Version

No response

Other Information

No response

Proposed Fix

No response

Contributing

Code of Conduct

KrishnaIyer commented 1 year ago

The general request looks ok. And you're using standard basic auth credentials base64 encoded "client-id:client-password"?

romach commented 1 year ago

The general request looks ok. And you're using standard basic auth credentials base64 encoded "client-id:client-password"?

Yes I do.

The issue is that error message invalid or missing request parameter is to vague. So I can't determine the reason for error.

KrishnaIyer commented 1 year ago

The Authorization Code is exactly 98 characters. So adding that to the request, the content length without whitespaces is 143 characters.

{"code":"MF2XI.JQ4KK77YEP4HAA3RHO2PJMK3F4JS4L37NDVEUMY.U4662YGK27JU4UXDQBJOXZ7NFK2GDP4TWK7UCQEB536ZBZAZXM3A","grant_type":"authorization_code"}

I see that the content length of your request is 156. Where do these extra characters come from? Are they simply whitespaces?

@adriansmares: Since the above Token request is explicitly POST, I see the E_INVALID_REQUEST (the OSIN error for this invalid_request) only if the parsing of the form failed. But we explicit set the form values before calling this function. Do you see something?

adriansmares commented 1 year ago

The problem here is that the redirect URI is not provided during the token exchange. The OAuth client which is affected here has multiple redirect URIs, and the first redirect URI in the OAuth client is probably different from the one requested during authorization.

Providing the redirect_uri explicitly in the body of the token exchange request should fix this issue. The redirect_uri is supposed to be provided by the caller explicitly during the token exchange, but for convenience osin will use the first redirect URI in case none is provided. It will still validate the redirect URI against the one provided in the authorization request, and since probably the implicit redirect URI is not matching that one, the error occurs.

This is mainly from the backend logs of the Identity Server. We don't propagate error causes from osin, but maybe in the future we can take a look if we should do it.