#23733 closed defect (invalid)
JOSM does not send client_secret in oauth2 token request for authorization code grant flow
Reported by: | Woazboat | Owned by: | Woazboat |
---|---|---|---|
Priority: | critical | Milestone: | |
Component: | Core | Version: | latest |
Keywords: | oauth2, client_secret | Cc: |
Description (last modified by )
Encountered on JOSM v19103 when using a local self-hosted OSM server
After pressing the 'Authorize now (Fully automatic)' button, the following HTTP exchange happens:
Authorization request -> OSM server
GET /oauth2/authorize?response_type=code&client_id=Z6bOm_8NT2JIEx5JDpV4iQwy1vD40Pc6HYAu4ugUWgc&redirect_uri=http://127.0.0.1:8111/oauth_authorization&scope=read_gpx%20write_gpx%20read_prefs%20write_prefs%20write_api%20write_notes&state=9c24c6cd-5572-410f-bab3-fa49c91a71cd&code_challenge_method=S256&code_challenge=JjuiikdPYf6hiXWwzZW5ydJur-lqn7AdC_mH0WBORDA HTTP/1.1 Host: localhost:31500 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8 Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate, br DNT: 1 Connection: keep-alive Cookie: _osm_session=f1dd39db183fe58b9806ee39742ecc9f Upgrade-Insecure-Requests: 1 Sec-Fetch-Dest: document Sec-Fetch-Mode: navigate Sec-Fetch-Site: none Sec-Fetch-User: ?1
OSM server sends the authorization code back to JOSM via the remote control url:
HTTP/1.1 302 Found X-Frame-Options: SAMEORIGIN X-XSS-Protection: 0 X-Content-Type-Options: nosniff X-Permitted-Cross-Domain-Policies: none Referrer-Policy: strict-origin-when-cross-origin Content-Language: en Location: http://127.0.0.1:8111/oauth_authorization?code=1Zhog9xRXeAsbRwVUgVvtubQkmWeBuY_kr7SY_pkVy8&state=9c24c6cd-5572-410f-bab3-fa49c91a71cd Content-Type: text/html; charset=utf-8 Cache-Control: no-cache Content-Security-Policy-Report-Only: default-src 'self'; child-src 'self'; connect-src 'self'; font-src 'none'; frame-ancestors 'self'; frame-src 'self'; img-src 'self' data: www.gravatar.com *.wp.com tile.openstreetmap.org gps.tile.openstreetmap.org *.tile.thunderforest.com tile.tracestrack.com *.openstreetmap.fr; manifest-src 'self'; media-src 'none'; object-src 'self'; script-src 'self'; style-src 'self' 'nonce-rbBl3U4wpaHEQJMZrruF+qw9tDDD+sXC'; worker-src 'none' Set-Cookie: _osm_session=f1dd39db183fe58b9806ee39742ecc9f; path=/; expires=Thu, 11 Jul 2024 13:17:31 GMT; HttpOnly; SameSite=Lax X-Request-Id: cc4fcc48-4d44-4d1c-80b2-600ff2ee7d2f X-Runtime: 0.120389 Server-Timing: start_processing.action_controller;dur=0.09, cache_read.active_support;dur=0.14, sql.active_record;dur=49.07, instantiation.active_record;dur=2.14, transaction.active_record;dur=16.65, redirect_to.action_controller;dur=0.14, process_action.action_controller;dur=87.95, cache_write.active_support;dur=0.10 vary: Accept-Language, Origin Content-Length: 0 Date: Thu, 13 Jun 2024 13:17:31 GMT Server: lighttpd/1.4.64
GET /oauth_authorization?code=1Zhog9xRXeAsbRwVUgVvtubQkmWeBuY_kr7SY_pkVy8&state=9c24c6cd-5572-410f-bab3-fa49c91a71cd HTTP/1.1 Host: 127.0.0.1:8111 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8 Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate, br DNT: 1 Connection: keep-alive Cookie: _xsrf=2|1ee5c13c|6a4925189a1640610ef6a475ff957ba5|1617984267; CSRF-Token-3KZHS=uydXZvUwRpA3Jud2FgNt4i3QUmFp7PUu; session=eyJjc3JmX3Rva2VuIjoiNWJlYjY1N2I0YTk0OTQwY2Y1M2RlN2EyYmNkMGEyODYxNzkzOTQ5MSJ9.Yq0O7g.ckj-pvRrRe21b4q7kb41nhU9tZQ Upgrade-Insecure-Requests: 1 Sec-Fetch-Dest: document Sec-Fetch-Mode: navigate Sec-Fetch-Site: none Sec-Fetch-User: ?1 Sec-GPC: 1
In response, JOSM sends a POST request to the token access URL to fetch the token. The body of this request is missing the required client_secret field.
POST /oauth2/token HTTP/1.1 User-Agent: JOSM/1.5 (19103 en) Linux Debian GNU/Linux trixie/sid Java/17.0.11 Accept: */* Accept-Encoding: gzip, deflate Content-Type: application/x-www-form-urlencoded Host: localhost:31500 Connection: keep-alive Content-Length: 238 Cookie: _osm_session=04f15c9d111f742de724847cd34caa4b grant_type=authorization_code&client_id=Z6bOm_8NT2JIEx5JDpV4iQwy1vD40Pc6HYAu4ugUWgc&redirect_uri=http://127.0.0.1:8111/oauth_authorization&code=1Zhog9xRXeAsbRwVUgVvtubQkmWeBuY_kr7SY_pkVy8&code_verifier=f7cfbb5d-87a2-4169-9cf3-62ed0020a9e4
As a result, the server rejects the token request:
HTTP/1.1 401 Unauthorized X-Frame-Options: SAMEORIGIN X-XSS-Protection: 0 X-Content-Type-Options: nosniff X-Permitted-Cross-Domain-Policies: none Referrer-Policy: strict-origin-when-cross-origin Cache-Control: no-store Content-Type: application/json; charset=utf-8 WWW-Authenticate: Bearer realm="Doorkeeper", error="invalid_client", error_description="Client authentication failed due to unknown client, no client authentication included, or unsupported authentication method." Content-Security-Policy-Report-Only: default-src 'self'; child-src 'self'; connect-src 'self'; font-src 'none'; form-action 'self'; frame-ancestors 'self'; frame-src 'self'; img-src 'self' data: www.gravatar.com *.wp.com tile.openstreetmap.org gps.tile.openstreetmap.org *.tile.thunderforest.com tile.tracestrack.com *.openstreetmap.fr; manifest-src 'self'; media-src 'none'; object-src 'self'; script-src 'self'; style-src 'self' 'nonce-XzjPNRrxCTsi4OWcceuk1Z/uJARIa2kH'; worker-src 'none' X-Request-Id: 1e9532ba-6621-4a14-8eb3-078c28565325 X-Runtime: 0.032401 Server-Timing: start_processing.action_controller;dur=0.02, sql.active_record;dur=1.51, instantiation.active_record;dur=0.29, process_action.action_controller;dur=12.66 vary: Accept, Origin Content-Length: 173 Date: Thu, 13 Jun 2024 13:17:31 GMT Server: lighttpd/1.4.64 {"error":"invalid_client","error_description":"Client authentication failed due to unknown client, no client authentication included, or unsupported authentication method."}
After manually modifying and re-sending the POST request to include the client_secret
field, the request succeeds and the server responds with a token:
(The following request logs for the modified request are from a different attempt, so the authorization codes/nonces are different)
POST /oauth2/token HTTP/1.1 User-Agent: JOSM/1.5 (19103 en) Linux Debian GNU/Linux trixie/sid Java/17.0.11 Accept: */* Accept-Encoding: gzip, deflate Content-Type: application/x-www-form-urlencoded Host: localhost:31500 Connection: keep-alive Content-Length: 296 Cookie: _osm_session=04f15c9d111f742de724847cd34caa4b grant_type=authorization_code&client_id=Z6bOm_8NT2JIEx5JDpV4iQwy1vD40Pc6HYAu4ugUWgc&client_secret=2TvpyFlxvu0C4b435d3lofB5dY7K4_qSKWoX6C0LEWM&redirect_uri=http://127.0.0.1:8111/oauth_authorization&code=IO4jNs0TqwV4o0Qxc0Itr1k-EzkttoI4s_EiAA5VxeA&code_verifier=bb1210fd-b70f-4d5b-b260-2264a2249f47
HTTP/1.1 200 OK X-Frame-Options: SAMEORIGIN X-XSS-Protection: 0 X-Content-Type-Options: nosniff X-Permitted-Cross-Domain-Policies: none Referrer-Policy: strict-origin-when-cross-origin Cache-Control: no-store Content-Type: application/json; charset=utf-8 ETag: W/"3ac628dafb309e963cfeaf02f5dab579" Content-Security-Policy-Report-Only: default-src 'self'; child-src 'self'; connect-src 'self'; font-src 'none'; form-action 'self'; frame-ancestors 'self'; frame-src 'self'; img-src 'self' data: www.gravatar.com *.wp.com tile.openstreetmap.org gps.tile.openstreetmap.org *.tile.thunderforest.com tile.tracestrack.com *.openstreetmap.fr; manifest-src 'self'; media-src 'none'; object-src 'self'; script-src 'self'; style-src 'self' 'nonce-i9hz2NMTdzxzWhLUI8Z4eCIksw+JEXzN'; worker-src 'none' X-Request-Id: b7b5e3e1-84a5-4f58-a090-269eed9e7620 X-Runtime: 0.051822 Server-Timing: start_processing.action_controller;dur=0.02, sql.active_record;dur=13.24, instantiation.active_record;dur=0.73, transaction.active_record;dur=18.50, process_action.action_controller;dur=33.36 vary: Accept, Origin Content-Length: 182 Date: Thu, 13 Jun 2024 13:30:25 GMT Server: lighttpd/1.4.64 {"access_token":"oxpk2rfgDuAlRMP0T25b5v3LNXJF99PK1451H8Rm1wM","token_type":"Bearer","scope":"read_gpx write_gpx read_prefs write_prefs write_api write_notes","created_at":1718284075}
The server is only used for local testing, so posting the secrets here is not an issue
References:
https://datatracker.ietf.org/doc/html/rfc6749#section-2.3.1
https://developer.okta.com/blog/2018/04/10/oauth-authorization-code-grant-type
https://www.oauth.com/playground/authorization-code.html
Attachments (1)
Change History (7)
by , 14 months ago
Attachment: | josm_custom_server_oauth2_settings.png added |
---|
comment:1 by , 14 months ago
Description: | modified (diff) |
---|
comment:2 by , 14 months ago
Description: | modified (diff) |
---|
follow-up: 5 comment:3 by , 14 months ago
RFC6749 section 2.3.1 ("Client Password") isn't currently supported by JOSM.
For starters, JOSM is not a "confidential" application -- since we distribute a jar file with the parameters, the client_secret
is by definition not secret. From section 2.1, when generating tokens for JOSM on osm.org, I chose the "public" (non-confidential) option. I only added the secret for the dev instance to make it easier for contributors to test functionality that required it.
We use the Authorization Code Grant
flow (section 4.1).
Specifically:
4.1.1: No client secret
4.1.2: No client secret
4.1.3: No client secret
OK. Where does the confidential application actually use the client secret:
2.3.1: Basic auth with authorization server. From what I understand, this should be disabled on osm.org anyway.
For this flow, I would have a user ("user") and password ("password123") which would be Authorization: Basic dXNlcjpwYXNzd29yZDEyMw==
with a POST like /token
and a body of grant_type=token&client_id=${client_id}&client_secret=${client_secret}
.
All that we can do with the client_secret is avoid opening a browser; this is generally considered bad practice for 3p clients anyway.
In any case, I specifically wrote our OAuth 2 implementation with a view towards "best practices".
comment:4 by , 14 months ago
Owner: | changed from | to
---|---|
Status: | new → needinfo |
I think your client_id might be wrong. Can you show the oauth2 settings from your local OSM server?
comment:5 by , 14 months ago
Ah, yes you are correct, this was a configuration error on my side and a misunderstanding about oauth. I left the 'confidential application' checkbox on the default 'on' state when registering the oauth application on the server. The token access request works after deselecting that setting.
Replying to taylor.smock:
OK. Where does the confidential application actually use the client secret:
2.3.1: Basic auth with authorization server. From what I understand, this should be disabled on osm.org anyway.
For this flow, I would have a user ("user") and password ("password123") which would beAuthorization: Basic dXNlcjpwYXNzd29yZDEyMw==
with a POST like/token
and a body ofgrant_type=token&client_id=${client_id}&client_secret=${client_secret}
.
As far as I understand it, only one of either basic auth or the client secret in the body should be used for client authentication. At least with the default configuration, the rails port accepts the client secret as authentication (as seen above). Not sure if the configuration for osm.org differs.
I think your client_id might be wrong. Can you show the oauth2 settings from your local OSM server?
The OSM website source doesn't include the default client id config for josm, so the one in the requests above is a custom one for a self-registered oauth application.
comment:6 by , 14 months ago
Resolution: | → invalid |
---|---|
Status: | needinfo → closed |
oauth2 settings