Opened 4 weeks ago
Closed 3 weeks ago
#24925 closed defect (fixed)
[PATCH] oauth2 for a non-OSM/OHM openstreetmap-website instance fails
| Reported by: | Owned by: | wangi | |
|---|---|---|---|
| Priority: | normal | Milestone: | 26.09 |
| Component: | Core | Version: | |
| Keywords: | template_report | Cc: |
Description
I have a problem with the user-facing way to authenticate JOSM against a non-OSM/OHM openstreetmap-website instance which has basic authentication disabled.
I have oauth2 set up for a Panoramax instance amongst other things so have some understanding of the issues.
My OSM website has a doorkeeper signing key and the JOSM Oauth 2 Appplication is set up in the normal way.
What steps will reproduce the problem?
Clear out JOSM preferences leaving only an oauth.access-token.parameters.OAuth20.https://osm.mysite.net/api' entry for my OSM website
In JOSM Version 19627, download an area and move a node.
Click upload that givies panels saying "Uploading data..." and "Obtain authentication to OSM server"
Click "Yes" and browser opens at my OSM website (osm.mysite.net)
Log in and the page gives the often mentioned "Missing required parameter:client_id" at:
Paste in the OSM website Client ID into the URL and resubmit.
- JOSM gives: "Failed to authenticate at the OSM server 'https://osm.mysite.net/api'. (no token configured)
- Browser gives: "HTTP Error 500: Internal Server Error: org.openstreetmap.josm.data.oauth.OAuth20Exception at the internal server address http://127.0.0.1:8111/oauth_authorization?code=p_bohEToJ1l3AOV8G3IAhXlgSB3KS5BxGK160iHX2Ow&state=22da5bc2-e3e1-4b85-a77e-38bba8d20b63
- Rails port console gives: Doorkeeper grant - "token", "p_bohEToJ1l3AOV8G3IAhXlgSB3KS5BxGK160iHX2Ow"
Back in JOSM Preferences, click "Authorise now (Manual)" and enter the token as the Access Token Key.
Clicking "Test Access Token " fails (Failed to access the OSM server 'https://osm.mysite.net/api' with the Access Token 'p_bohEToJ1l3AOV8G3IAhXlgSB3KS5BxGK160iHX2Ow'.The server rejected the Access Token as unauthorised.)
Rails port console now has a second Doorkeeper entry with "token", "06cc923ca6d5a1cb1175bc6a608581b5e394a6dccc7b11119f16a15ceb4be33d"
As expected, nothing has been written to preferences.xml.
JOSM is frozen
Restart JOSM, enter the advanced manual information, click "Authorise now (manual)" and enter the second token.
The second token fails with "Failed to retrieve information about the current user from the OSM server 'https://osm.mysite.net/api')
What is the expected result?
Authentication
What happens instead?
Authenticaion fails
Please provide any additional information below. Attach a screenshot if possible.
Relative:URL: ^/trunk Repository:UUID: 0c6e7542-c601-0410-84e7-c038aed88b3b Last:Changed Date: 2026-09-20 21:33:09 +0200 (Sun, 20 Sep 2026) Revision:19627 Build-Date:2026-09-21 01:30:50 URL:https://josm.openstreetmap.de/svn/trunk Identification: JOSM/1.5 (19627 en_GB) Windows 11 64-Bit OS Build number: Windows 10 Pro 25H2 (26200) Memory Usage: 712 MB / 16328 MB (433 MB allocated, but free) Java version: 18.0.1.1+2-6, Oracle Corporation, Java HotSpot(TM) 64-Bit Server VM Look and Feel: com.sun.java.swing.plaf.windows.WindowsLookAndFeel Screen: \Display0 1920x1080x32bpp@60Hz (scaling 1.00×1.00) Maximum Screen Size: 1920×1080 Best cursor sizes: 16×16→32×32, 32×32→32×32 System property file.encoding: UTF-8 System property sun.jnu.encoding: Cp1252 Locale info: en_GB Numbers with default locale: 1234567890 -> 1234567890 Plugins: + ImportImagePlugin (36503) + PicLayer (275) + apache-commons (36483) + ejml (36483) + geotools (36483) + imagery_offset_db (36503) + jackson (36502) + jaxb (36483) + jts (36483) + mbtiles (v2.8.1) + photo_geotagging (36503) + photoadjust (36503) Last errors/warnings: - 00000.372 W: extended font config - overriding 'filename.Myanmar_Text=mmrtext.ttf' with 'MMRTEXT.TTF' - 00000.373 W: extended font config - overriding 'filename.Mongolian_Baiti=monbaiti.ttf' with 'MONBAITI.TTF' - 00002.023 W: Update plug-ins - You updated your JOSM software. To prevent problems the plug-ins should be updated as well. Update plug-ins now? OSM API: https://osm.mysite.net/api
Attachments (1)
Change History (10)
comment:1 by , 4 weeks ago
comment:2 by , 4 weeks ago
To answer myself... I commented out my test server from OAuthParameters.java.
- Clear out authentication, put in the custom API, validate and close dialog... Make an edit, upload and get the same issue as OP.
- Clear out authentication, put in the custom API, validate, show advanced OAuth params, enter client ID and secret from a created non-confidential OAuth 2 Application on the site with the correct perms and redirect URL, authorise automatically = success
comment:3 by , 4 weeks ago
Thank you for the feedback. I'll have a look at having up-front preferences.
comment:4 by , 4 weeks ago
I think the second works (I am checking to see that a node in the database is added).
I simply removed the tag for the key='oauth.access-token.parameters.OAuth20.https://osm.mysite.net/api' from preferences.xml.
Closed the browser, ran JOSM and added the Advanced Oauth Parameters.
The automatic button was now active: Clicking the button opened the browser at the OSM-website login. Logged in and received a page saying 'OK'.
An Access Token Key was now displayed in JOSM.
If the database is indeed updated, many, many thanks. Being able to use JOSM with a self-hosted Oauth2 OSM-website is essential
comment:6 by , 4 weeks ago
| Owner: | changed from to |
|---|---|
| Status: | new → assigned |
| Summary: | oauth2 for a non-OSM/OHM openstreetmap-website instance fails → [PATCH] oauth2 for a non-OSM/OHM openstreetmap-website instance fails |
by , 4 weeks ago
| Attachment: | oauth-auth-on-upload.patch added |
|---|
comment:7 by , 4 weeks ago
Attached is a patch against r19627.
What goes wrong
The advanced OAuth parameters and the access token are stored under different keys.
OAuth20Parameters.rememberPreferences()stores the parameters under the API URL:oauth.access-token.parameters.OAuth20.https://example.org/apiOAuthAccessTokenHolderandCredentialsManagerkey the token by host, becausegetAccessToken()/setAccessToken()reduce whatever they are given withURI.create(api).getHost().
OsmConnection.addOAuth20AuthorizationHeader(), which is the path taken on upload when there is no token yet, resolved the parameters with the host:
this.oAuth20Parameters = OAuthParameters.createFromApiUrl(connection.getURL().getHost(), OAuthVersion.OAuth20);
so createFromPreferences() looked for …OAuth20.example.org, missed, and fell through to createDefault(). There the host is not a valid URL, so it was replaced by the API URL configured in the preferences, which matches none of the switch cases of the servers JOSM has a client id for, and the client id ended up as the empty string. JOSM then opened the browser at the authorization endpoint with client_id=, which the server rejects with "Missing required parameter: client_id" — exactly as reported.
That also explains the later steps of the report. Once you fall back to entering the token by hand, ManualAuthorizationUI builds new OAuth20Token(getOAuthParameters(), …) from those same parameters, and OAuth20Token.sign() rejects the request if their api_url does not contain the host being called. Hence the authorization being refused and "Test Access Token" failing even though the token itself was good.
Measured on an unmodified checkout, with the parameters saved as the authentication preferences save them and the RFC 8414 lookup disabled so that only the local logic runs:
pref 'oauth.access-token.parameters.OAuth20.https://nonprod-mapops.example.org/api' = {"client_id":"MY_CLIENT_ID", …}
pref 'oauth.access-token.parameters.OAuth20.nonprod-mapops.example.org' = <unset>
createFromApiUrl(apiUrl) clientId = 'MY_CLIENT_ID' <-- the authentication preferences
createFromApiUrl(host) clientId = '' <-- OsmConnection, on upload
This is also why doing the whole setup in the preferences works, as noted in comment 2: "Authorize now" passes the API URL, the upload path passed the host.
The patch
OsmConnection.addOAuth20AuthorizationHeader()looks the parameters up with the API URL (OsmApi.getOsmApi().getServerUrl()) instead of the host.createFromApiUrl()reduces it to the host itself where that is what it needs, for the token lookup. This is safe at both call sites ofaddAuth():OsmApionly authenticates its own requests, andOsmServerReaderalready guards withObjects.equals(this.api.getHost(), client.getURL().getHost()).OAuthParameters.createFromApiUrl()passes the URL as it was given tocreateDefault(). It passed the already shortened host, and since a host is never a valid URL,createDefault()silently fell back to the API configured in the preferences. Asking for the parameters of any other server therefore returned the configured server's: with a third-party API configured,createFromApiUrl("https://api.openhistoricalmap.org/api")returned an empty client id rather than OHM's.- No client id means no authorization request.
obtainOAuth20Token()now gives up before asking whether to open a browser, instead of sending the user to a page the server will reject. The message of the exception is for the log only; what the user is shown already says to open the preferences, which is where the client id of an OAuth application registered on that server is entered. No new translatable strings.
Unit tests
- New
OsmConnectionTest: the OAuth parameters of a connection come from the configured API URL and the connection is signed (non-regression test for this ticket); an existing token signs the connection without the parameters having to be stored; and a missing client id fails before the user is asked anything. The last one pre-answers the confirmation dialog with "No", so that it still terminates quickly rather than waiting out the five minute authorization timeout if the check is ever removed — what tells the two apart is that only the check names the server it gave up on. OAuthParametersTest:createFromApiUrl()answers for the server it is asked about whichever server is configured, and finds the parameters that were remembered under the API URL.
Each of the three changes was reverted on its own to confirm the corresponding test fails without it. Note that @BasicPreferences does not reset the preferences between the test methods of a class, so both test classes clear the API URL and the remembered parameters in @AfterEach; without that the leaked parameters from one test masked the missing client id in another.
159 tests in org.openstreetmap.josm.data.oauth, org.openstreetmap.josm.gui.oauth, org.openstreetmap.josm.gui.preferences.server, org.openstreetmap.josm.io.auth, org.openstreetmap.josm.io.Osm*, UserIdentityManagerTest and MessageNotifierTest behave the same as before; the three failures among them (OAuth20AuthorizationTest twice and OsmReaderTest.testMissingVersion) are present on an unmodified checkout as well. Checkstyle is clean.
Not fixed here
This is the smallest change that makes authentication on upload work. It does not touch the wider problem that tokens are keyed by host and parameters by API URL, that the endpoints fall back to guessing <api url>/authorize when a server publishes no RFC 8414 metadata (wrong for every openstreetmap-website instance), or that there is no good place to paste an access token. Those, together with dropping Basic Authentication and the unused authorization procedures, are collected in a separate ticket for discussion before anything is written.
comment:8 by , 4 weeks ago
| Milestone: | → 26.09 |
|---|



Just to join the dots, r19627 is when #24890 and #24889 were merged, both OAuth related.
I note the step you clear configuration out and then only try to complete the process on upload. What happens if you try to do it all upfront in the preferences dialog?