You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
The oauth2-server.Request is not compatible to Fetch API Request #356
The oauth2-server.Request is not compatible to Fetch API Request, "Missing parameter: query"
To Reproduce
Steps to reproduce the behavior:
use a framework like SvelteKit that uses Fetch API Requests
build a request handler that passes down Request to oauth2server
See error:
invalid_argument: Missing parameter: `query`
statusCode: 500,
status: 500,
code: 500,
at new OAuthError (/app/node_modules/@node-oauth/oauth2-server/lib/errors/oauth-error.js:13:5)
at new InvalidArgumentError (/app/node_modules/@node-oauth/oauth2-server/lib/errors/invalid-argument-error.js:21:5)
at new Request (/app/node_modules/@node-oauth/oauth2-server/lib/request.js:21:13)
Expected behavior
Try to get query via request.url (e.g.: new URL(request.url).searchParams
Screenshots
Additional context
In the examples (e.g. express server) requests are passed down to the oauth server. While express is probably the most used framework, I don't see why the default Request shouldn't be supported.
Which is wrong use of typescript since it leads to a runtime Error which is bypassing typescripts checks. Correct would be to omit all of the questions marks.
I'm not 100% sure this is relevant, but I'm experiencing the following error attempting to update to 5.2.1 from 5.2.0 passing an Express 5 ExpressRequest.query as the query property in a new OAuthRequest argument object.
error TS2322: Type 'ParsedQs' is not assignable to type 'Record<string, string>'.
'string' index signatures are incompatible.
Type 'string | ParsedQs | (string | ParsedQs)[]' is not assignable to type 'string'.
Type 'ParsedQs' is not assignable to type 'string'.
I'm not 100% sure this is relevant, but I'm experiencing the following error attempting to update to 5.2.1 from 5.2.0 passing an Express 5 ExpressRequest.query as the query property in a new OAuthRequest argument object.
error TS2322: Type 'ParsedQs' is not assignable to type 'Record<string, string>'.
'string' index signatures are incompatible.
Type 'string | ParsedQs | (string | ParsedQs)[]' is not assignable to type 'string'.
Type 'ParsedQs' is not assignable to type 'string'.
Releasing 5.2.1 with typing the headers and query parameters has broken a lot of compile time checks due to slight variations in different middleware's typing of those same properties.
This update should probably be rolled back or thoughtfully considered as to how it can be changed to accommodate the numerous scaffolding projects out there (Express, Koa, ....)
You can probably use tsc but I guess there is too much variation to cover all possible use cases no?
You can also union it with unknown aka Record<string, string | unknown>
@netizen01@KeithGillette I am currently workin on this to make it work with express request but also fetch api. I wonder why the express request is not covered by http.IncomingMessage as express request is a direct instance of its prototype.
Dear all, I created a new PR that uses tsd to explicitly write tests for types compatibility and to avoid regressions like this one in the future!
I think this is a necessary step towards a full typescript codebase in the long run. Please also use it as a basis for further discussion on how we can solve this issue.
Sorry to disagree but I've not only encountered the problem myself but you can easily verify the issue yourself. If you want to, you can look at the native Request Documentation on MDN and try to search "query". You will see that "query" is not a field in the Request class.
So you can't instanciate a Request into node-oauth Request like:
import{RequestasOauth2Request}from"node-oauth2-server";constnativeRequest=newRequest(/* some parameters */);constoauthRequest=newOauth2Request(nativeRequest);
Since this fails, due to the query parameter missing, I can imagine that some workflows might work but maybe not all.
Or is the query parameter not used? I'm not very deep into the inner workings of the library but there should be a reason this is required in the first place, right?
@FlorianB-DE yes, query is used in various places to extract access_token, scope, state or redirect_uri, depending on the workflow position.
Since this is a server-side lib, I wonder how you actually pass down the "native" request to the library. Can you please show me a short snippet of your request handler on the server?
@FlorianB-DE I get that but from what I see you should rather write an adapter for it, instead of passing it raw to the application. This is what the library is designed for. I did not realize this when you opened the PR but the correct way to support svelte kit right now is to write an adapter, specific to the framework.
There you can parse the request to construct a request that fits the OAuth2Server API.
One could argue that fetch is native and standard, however it's just recently standard in node and we aim for backwards-compatibility across major versions. Apologies again for not realizing this in the first place.
If you think this makes sense and intend to write an adapter for svelte kit then we can also write it in a new repo in this org to let others benefit from it, too. let me know if this is considerable to you.
@netizen01@KeithGillette I am currently workin on this to make it work with express request but also fetch api. I wonder why the express request is not covered by http.IncomingMessage as express request is a direct instance of its prototype.
var req = Object.create(http.IncomingMessage.prototype)
any input on this would be much appreciated.
with the following error on the query property of the argument:
TS2322: Type ParsedQs is not assignable to type Record<string, string>
string index signatures are incompatible.
Type string | ParsedQs | (string | ParsedQs)[] is not assignable to type string
Type ParsedQs is not assignable to type string
However, the following simplified implementation works fine:
To untangle this thread, there are really two separate things here:
A — first-class Fetch Request support (the original title). A Fetch Request has no query (only .url), headers is a Headers object, and the body is an async stream. Our Request constructor is synchronous and expects an already-parsed body, so this can't be solved in the constructor — it needs an adapter (await the body, derive query from new URL(req.url).searchParams, convert Headers → object) or a dedicated async entry point. This stays open as a feature to design (adapter vs built-in).
B — typing regression for Express/Koa (raised by @netizen01, @KeithGillette, @MartinKolarik). Since 5.2.1 (#362) the Request constructor typed headers/query as Record<string, string>, which rejects Express 5 req.query (ParsedQs) and Koa IncomingHttpHeaders at compile time. Fixed in #446: widened to Record<string, any>.
Why Record<string, any> and not string | string[]? Express 5's ParsedQs allows nested objects and undefined, so a narrower union still wouldn't accept it. The change is a backwards-compatible widening (existing Record<string, string> callers still compile), and headers/method/query stay required — so a raw Fetch Request (no query) still correctly fails to type-check rather than compiling and throwing at runtime.
Leaving this issue open for A (Fetch first-class support). Thanks all for the detailed reports.
Activity
FlorianB-DE commentedon Jun 12, 2025
Also note to that:
The type declarations state:
Which is wrong use of typescript since it leads to a runtime Error which is bypassing typescripts checks. Correct would be to omit all of the questions marks.
jankapunkt commentedon Jul 22, 2025
@FlorianB-DE released in 5.2.1. Closing this, feel free to reopen if necessary
FlorianB-DE commentedon Jul 22, 2025
Well I mean it's still not compatible but at least now the typescript type checker also knows this :D
jankapunkt commentedon Jul 22, 2025
I reopened. Let me check what's possible without hard breaking things.
netizen01 commentedon Jul 24, 2025
Weighing in here...
The headers and query properties need to accept string arrays as well.
Please amend your pull request appropriately...
KeithGillette commentedon Jul 29, 2025
I'm not 100% sure this is relevant, but I'm experiencing the following error attempting to update to 5.2.1 from 5.2.0 passing an Express 5
ExpressRequest.queryas thequeryproperty in a newOAuthRequestargument object.Express5
ReqQuery = ParsedQs:netizen01 commentedon Jul 29, 2025
This is the same issue that I have.
Releasing 5.2.1 with typing the headers and query parameters has broken a lot of compile time checks due to slight variations in different middleware's typing of those same properties.
This update should probably be rolled back or thoughtfully considered as to how it can be changed to accommodate the numerous scaffolding projects out there (Express, Koa, ....)
jankapunkt commentedon Jul 29, 2025
Thank you guys for reporting this. Is there a way to incorporate these kinds of checks into the test suite for example using tsc?
FlorianB-DE commentedon Jul 29, 2025
You can probably use tsc but I guess there is too much variation to cover all possible use cases no?
You can also union it with unknown aka
Record<string, string | unknown>jankapunkt commentedon Aug 11, 2025
@netizen01 @KeithGillette I am currently workin on this to make it work with express request but also fetch api. I wonder why the express request is not covered by
http.IncomingMessageas express request is a direct instance of its prototype.any input on this would be much appreciated.
// cc @dhensby
jankapunkt commentedon Aug 11, 2025
Dear all, I created a new PR that uses
tsdto explicitly write tests for types compatibility and to avoid regressions like this one in the future!I think this is a necessary step towards a full typescript codebase in the long run. Please also use it as a basis for further discussion on how we can solve this issue.
jankapunkt commentedon Aug 11, 2025
@FlorianB-DE please also take a look at these tests, using the "native" Request signature which seems to be working when passing down as-is.
FlorianB-DE commentedon Aug 11, 2025
Sorry to disagree but I've not only encountered the problem myself but you can easily verify the issue yourself. If you want to, you can look at the native Request Documentation on MDN and try to search "query". You will see that "query" is not a field in the Request class.
So you can't instanciate a Request into node-oauth Request like:
Since this fails, due to the query parameter missing, I can imagine that some workflows might work but maybe not all.
Or is the query parameter not used? I'm not very deep into the inner workings of the library but there should be a reason this is required in the first place, right?
jankapunkt commentedon Aug 11, 2025
@FlorianB-DE yes, query is used in various places to extract access_token, scope, state or redirect_uri, depending on the workflow position.
Since this is a server-side lib, I wonder how you actually pass down the "native" request to the library. Can you please show me a short snippet of your request handler on the server?
FlorianB-DE commentedon Aug 11, 2025
E.g. Sveltekit uses Fetch API standards for Server-Side request handling:
https://svelte.dev/docs/kit/web-standards#Fetch-APIs-Request
jankapunkt commentedon Aug 11, 2025
@FlorianB-DE I get that but from what I see you should rather write an adapter for it, instead of passing it raw to the application. This is what the library is designed for. I did not realize this when you opened the PR but the correct way to support svelte kit right now is to write an adapter, specific to the framework.
You can get inspiration by the express adapter: https://github.com/node-oauth/express-oauth-server
There you can parse the request to construct a request that fits the OAuth2Server API.
One could argue that fetch is native and standard, however it's just recently standard in node and we aim for backwards-compatibility across major versions. Apologies again for not realizing this in the first place.
If you think this makes sense and intend to write an adapter for svelte kit then we can also write it in a new repo in this org to let others benefit from it, too. let me know if this is considerable to you.
KeithGillette commentedon Aug 11, 2025
I revisited this and found the following oddity.
This is an excerpt of our implementation that broke with 5.2.1:
with the following error on the
queryproperty of the argument:However, the following simplified implementation works fine:
MartinKolarik commentedon Jan 26, 2026
With
koa, we currently passctx.request, which works at runtime but fails at the type level with the headers definition in5.2.1because:IncomingHttpHeaderswhere values arestring | undefinedwhich doesn't pass forRecord<string, string>IncomingMessage, so that fails too.Passing the raw
ctx.reqmatches type-wise as it'sIncomingMessage, but there's noquery, so it fails at runtime.dhensby commentedon Jun 16, 2026
To untangle this thread, there are really two separate things here:
A — first-class Fetch
Requestsupport (the original title). A FetchRequesthas noquery(only.url),headersis aHeadersobject, and the body is an async stream. OurRequestconstructor is synchronous and expects an already-parsedbody, so this can't be solved in the constructor — it needs an adapter (await the body, derivequeryfromnew URL(req.url).searchParams, convertHeaders→ object) or a dedicated async entry point. This stays open as a feature to design (adapter vs built-in).B — typing regression for Express/Koa (raised by @netizen01, @KeithGillette, @MartinKolarik). Since
5.2.1(#362) theRequestconstructor typedheaders/queryasRecord<string, string>, which rejects Express 5req.query(ParsedQs) and KoaIncomingHttpHeadersat compile time. Fixed in #446: widened toRecord<string, any>.Leaving this issue open for A (Fetch first-class support). Thanks all for the detailed reports.