Modify ↓

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: petergboswell@… 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:

​https://osm.mysite.net/oauth2/authorize?response_type=code&client_id=&redirect_uri=http://127.0.0.1:8111/oauth_authorization&scope=read_gpx%20write_gpx%20read_prefs%20write_prefs%20write_api%20write_notes&state=22da5bc2-e3e1-4b85-a77e-38bba8d20b63&code_challenge_method=S256&code_challenge=Lxtb2JyoY6iCTIj9jzNOxSUzAZSgjROSq02hdT8Cdek

Paste in the OSM website Client ID into the URL and resubmit.

  • 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)

oauth-auth-on-upload.patch​ (13.8 KB ) - added by wangi 4 weeks ago.

Download all attachments as: .zip

Change History (10)

comment:1 by wangi, 4 weeks ago

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?

comment:2 by wangi, 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 petergboswell@…, 4 weeks ago

Thank you for the feedback. I'll have a look at having up-front preferences.

comment:4 by anonymous, 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:5 by anonymous, 4 weeks ago

The database is updated!

comment:6 by wangi, 4 weeks ago

Owner: changed from team to wangi
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 wangi, 4 weeks ago

Attachment: oauth-auth-on-upload.patch​ added

comment:7 by wangi, 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/api
  • OAuthAccessTokenHolder and CredentialsManager key the token by host, because getAccessToken()/setAccessToken() reduce whatever they are given with URI.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 of addAuth(): OsmApi only authenticates its own requests, and OsmServerReader already guards with Objects.equals(this.api.getHost(), client.getURL().getHost()).
  • OAuthParameters.createFromApiUrl() passes the URL as it was given to createDefault(). 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 stoecker, 4 weeks ago

Milestone: → 26.09

comment:9 by stoecker, 3 weeks ago

Resolution: → fixed
Status: assigned → closed

In 19638/josm:

oauth2 for a non-OSM fails setup on upload, patch by wangi, fix #24925

Modify Ticket

Change Properties
Set your email in Preferences
Action
as closed The owner will remain wangi.
as The resolution will be set.
The resolution will be deleted. Next status will be 'reopened'.

Add Comment


E-mail address and name can be saved in the Preferences .
 
Note: See TracTickets for help on using tickets.