Spring Boot, JavaScript fetching Endpoint
Hi, my method getSeconds() is not invoked.
@PostMapping("/get-seconds")
public ResponseEntity<Integer> getSeconds(@RequestBody ModulUpdateRequest request) {
log.info("called get-seconds");
return ResponseEntity.ok(modulService.getSecondsForId(UUID.fromString(request.fachId())));
}
this is my fetch:
export async function getSeconds(fachId) {
try {
const csrfToken = getCsrfToken();
console.log("csrf=" + csrfToken)
const response = await fetch('/api/get-seconds', {
method: 'POST',
credentials: "include",
headers: {
'Content-Type': 'application/json',
'X-XSRF-TOKEN': csrfToken
},
body: JSON.stringify({ fachId })
});
console.log(response)
//if (!response.ok) {
// throw new Error(
HTTP error! Status: ${response.status});
//}
return await response.text();
} catch (error) {
//console.error('Fehler beim Abrufen der Sekunden:', error);
}
}
118 Replies
⌛
This post has been reserved for your question.
Hey @Suika! Please useTIP: Narrow down your issue to simple and precise questions to maximize the chance that others will reply in here./close
or theClose Post
button above when your problem is solved. Please remember to follow the help guidelines. This post will be automatically marked as dormant after 300 minutes of inactivity.
I am using Spring Security with:
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http.authorizeHttpRequests(authz -> authz
.requestMatchers("/styles/**", "/js/**", "/api/get-seconds").permitAll()
.anyRequest().authenticated()
)
.csrf(csrf -> csrf.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()))
.oauth2Login(oauth2 -> oauth2
.userInfoEndpoint(
info -> info.userService(new AppUserService())
)
.loginPage("/oauth2/authorization/github")
.defaultSuccessUrl("/dashboard", true)
);
return http.build();
}
This i what my console says:
Response { type: "basic", url: "http://localhost:8080/api/get-seconds", redirected: false, status: 403, ok: false, statusText: "", headers: Headers(11), body: ReadableStream, bodyUsed: false }
my backend says: Resolved [org.springframework.web.HttpRequestMethodNotSupportedException: Request method 'GET' is not supported]
when i use my browser and type in localhost:8080/api/get-secondswell thats because you are using post mapping in your backend
which is a post request
and you are calling a get request
where am i calling a get request?
@PostMapping("/get-seconds")
method: 'POST'
im really confused
this test is green:
void test_01() throws Exception {
ModulUpdateRequest request = new ModulUpdateRequest(UUID.randomUUID().toString(), 10);
mvc.perform(post("/api/get-seconds")
.contentType(MediaType.APPLICATION_JSON)
.content(new ObjectMapper().writeValueAsString(request))
.with(csrf()))
.andExpect(status().isOk());
}
here you are calling post
but here it says you tried to call the endpoint using get
yes
thats whats weird
look my getSeconds method
it says method: 'POST'
thats what my problem is
can you try postman
and its a problem since i activated spring security
and see if it works
ill try
try to send the requests using postman
see if its gonna have the same result
its not but im not sure if i use postman right with this. i get:
Error parsing HTTP request header
Note: further occurrences of HTTP request parsing errors will be logged at DEBUG level.
java.lang.IllegalArgumentException: Invalid character found in method name [0x160x030x010x000xf70x010x000x000xf30x030x030x02=0xcc0x7f0xf50xdc0x950x11 ]. HTTP method names must be tokens
show the postman request
i mean
how you set it up



public record ModulUpdateRequest(
@JsonProperty("fachId") String fachId,
@JsonProperty("secondsLearned") int secondsLearned
) {
@JsonCreator
public ModulUpdateRequest { }
}
hmmm
can you disable oauth in your code and see if it helps
maybe thats the problem
i ve turned off spring security completely and its the same lol
ok it works now with security off
i mean my endpoint works
with the javascript fetch
can you turn on security on but disable csrf with
but if secuity is set up it doesnt
ill try
ok it works
ok so the problem is your csrf configuration
ok
but its weird
i get the scrf token as a cookie and i can retrieve it with java script
function getCsrfToken() {
return document.cookie
.split('; ')
.find(row => row.startsWith('XSRF-TOKEN='))
?.split('=')[1];
}
csrf.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()))i think this code is the problem
thats what cpgt has adviced
so that i could use the crsf value
if i use thymeleaf
and th:action
there would be no problem
but im using this fetch-method
so i needed to include this token into the request
hmmmm
i now also commented out
.csrf(AbstractHttpConfigurer::disable);
ok lets maybe ask someone more competent than me lmao
@dan1st | Daniel can you take a look
csrf setup throws an error
but when its disabled the stuff works fine
this line specifically
What's the exact error/stack trace?
its a post endpoint tho
and that's the code calling it?
heres postman
now its:
export async function getSeconds(fachId) {
try {
const csrfToken = getCsrfToken();
const response = await fetch('/api/get-seconds', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ fachId}) // Send fachId in a JSON object
});
console.log(response)
//if (!response.ok) {
// throw new Error(
HTTP error! Status: ${response.status});
//}
return await response.text();
} catch (error) {
//console.error('Fehler beim Abrufen der Sekunden:', error);
}
}
i disabled csrf so im not packing it into headerCan you show the request in thenetwork tab in the browser devtools?
Does the same error occur with both
fetch()
amdpostman?with disabled csrf seems to work
on postman
What happens in postman without disabled CSRF?
I assume a 403?

POSTMAN: POST https://localhost:8080/api/get-seconds
Error: write EPROTO 54397824:error:100000f7:SSL routines:OPENSSL_internal:WRONG_VERSION_NUMBER:........\src\third_party\boringssl\src\ssl\tls_record.cc:231:
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http.authorizeHttpRequests(authz -> authz
.requestMatchers("/styles/**", "/js/**").permitAll()
.anyRequest().authenticated()
)
//.csrf(AbstractHttpConfigurer::disable)
.oauth2Login(oauth2 -> oauth2
.userInfoEndpoint(
info -> info.userService(new AppUserService())
)
.loginPage("/oauth2/authorization/github")
.defaultSuccessUrl("/dashboard", true))
;
Is that with or without CSRF protection?
maybe because i need to send oauth2 token?
with
so without the
.csrf(AbstractHttpConfigurer::disable)
yes its commented out stil
well you didn't include a CSRF token so why would you expect anything else?
yes thats why i used:
csrf.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()))
and
function getCsrfToken() {
return document.cookie
.split('; ')
.find(row => row.startsWith('XSRF-TOKEN='))
?.split('=')[1];
}
to get the tokenwell you didn't add the CSRF token to the request I think
and send it:
const csrfToken = getCsrfToken();
This message has been formatted automatically. You can disable this using
/preferences
.sure it should be
X-CRSF
?i was when i had it to this point, thats what i remember, i copied cpgt solution
it should normally be
X-XSRF-TOKEN
yes
im trying again
The CookieCsrfTokenRepository writes to a cookie named XSRF-TOKEN and reads it from an HTTP request header named X-XSRF-TOKEN or the request parameter _csrf by default. These defaults come from Angular and its predecessor AngularJS.
const csrfToken = getCsrfToken();
const response = await fetch('/api/get-seconds', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-XSRF-TOKEN': csrfToken
},
body: JSON.stringify({ fachId}) // Send fachId in a JSON object
});
http.authorizeHttpRequests(authz -> authz
.requestMatchers("/styles/**", "/js/**").permitAll()
.anyRequest().authenticated()
)
.csrf(csrf -> csrf.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()))
.oauth2Login(oauth2 -> oauth2
.userInfoEndpoint(
info -> info.userService(new AppUserService())
)
.loginPage("/oauth2/authorization/github")
.defaultSuccessUrl("/dashboard", true))
;
same
and same postman error like before
my endpoint is not invoked
public record ModulUpdateRequest(
@JsonProperty("fachId") String fachId,
@JsonProperty("secondsLearned") int secondsLearned
) {
@JsonCreator
public ModulUpdateRequest { }
}
enable TRACE or DEBUG logging with Spring Security: https://stackoverflow.com/a/47729991/10871900
Stack Overflow
How do I enable logging for Spring Security?
I am setting up Spring Security to handle logging users in. I have logged in as a user, and am taken to an Access Denied error page upon successful login. I don't know what roles my user has actually
then make the request
and check the logs
and also show the exact request and response in the browser devtools
this is in my backend now:
Error parsing HTTP request header
Note: further occurrences of HTTP request parsing errors will be logged at DEBUG level.
java.lang.IllegalArgumentException: Invalid character found in method name [0x160x030x010x000xf70x010x000x000xf30x030x030xe10xdf(0xbe0xf10xc7(0xf1y0xac0xe18v0xdc0xc70x820xf70xc70xcaMo)o0x98|0xb80xf3!0xef0xf50xef0xc7 ]. HTTP method names must be tokens
at org.apache.coyote.http11.Http11InputBuffer.parseRequestLine(Http11InputBuffer.java:406) ~[tomcat-embed-core-10.1.34.jar:10.1.34]
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:270) ~[tomcat-embed-core-10.1.34.jar:10.1.34]
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63) ~[tomcat-embed-core-10.1.34.jar:10.1.34]
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:905) ~[tomcat-embed-core-10.1.34.jar:10.1.34]
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1741) ~[tomcat-embed-core-10.1.34.jar:10.1.34]
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52) ~[tomcat-embed-core-10.1.34.jar:10.1.34]
at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1190) ~[tomcat-embed-core-10.1.34.jar:10.1.34]
at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) ~[tomcat-embed-core-10.1.34.jar:10.1.34]
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:63) ~[tomcat-embed-core-10.1.34.jar:10.1.34]
at java.base/java.lang.Thread.run(Thread.java:833) ~[na:na]
You are running it locally, right?
like not on a server on the internet
correct
Are you using HTTPs?
this looks like attepting to use HTTPs on a HTTP-only server
stupid question but where do i see this when i use localhost
Can you show the stuff in the network tab?
the request
this?

Can you scroll up on the right?
Version: HTTP/1.1
?
POST
there should be something above the "Status: 403"
Also can you show the full logs?

ok it doesn't try to use HTTPs
Can you show the full logs?
which one do you mean
the Spring logs
stdout
console
it sais invalid CSRF token
so the CSRF token in the request isn't valid
Can you scroll down in the request headers (Anfragekopfzeilen)?

there should be an entry about CSRF
why is there no entry when i send this:
headers: {
'Content-Type': 'application/json',
'X-XSRF-TOKEN': csrfToken
},
that's what we are trying to find out
So you said there's no entry for it
ah ok
Can you print the value of
csrfToken
right before sending the request?
Is it maybe undefined
or null

yes
so the csrf in the second print is the actually the first one?
i mean the first one send by the server
the first one is undefined so that can't work
yes
when i visit /dashboard
there is no cookie for csrf
i need to send a cookie with GET?
no
but you are stil printing it and you are executing POST requests there
Can you show more of your JS code?
Like the code that's calling the thing computing the CSRF token and sending the request
like what's between these things etc
You are calling get-seconds twice. Can you check whether both of these requests have no CSRF token?
like is the CSRF token missing with both requests?
or just the first one?
export async function getSeconds(fachId) {
try {
const csrfToken = getCsrfToken();
console.log("csrf token=" + csrfToken)
const response = await fetch('/api/get-seconds', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-XSRF-TOKEN': csrfToken
},
body: JSON.stringify({ fachId}) // Send fachId in a JSON object
});
console.log(response)
//if (!response.ok) {
// throw new Error(
HTTP error! Status: ${response.status});
//}
return await response.text();
} catch (error) {
//console.error('Fehler beim Abrufen der Sekunden:', error);
}
}
function getCsrfToken() {
return document.cookie
.split('; ')
.find(row => row.startsWith('XSRF-TOKEN='))
?.split('=')[1];
}
async function startTimer(fachId) {
let seconds = await api.getSeconds(fachId);
if (running) {
timer = setInterval(() => seconds = updateTime(fachId, seconds), 1000);
} else {
running = false;
}
}
document.addEventListener("DOMContentLoaded", function() {
document.querySelectorAll(".start-button").forEach(button => {
button.addEventListener("click", function() {
const fachId = this.dataset.fachid;
if(running) {
clearInterval(timer);
api.postFinishInterval(fachId)
api.postNewSeconds(fachId)
changeButtonSymbol(fachId, PLAY);
} else {
api.postStartInterval(fachId);
changeButtonSymbol(fachId, STOP);
startTimer(fachId)
}
running = running === false;
});
});
});
its not called twice now
but its still undefined in the first time
i mean when i restart the app
the token is undefined
when i call getSecondas again it has a tokenThere are requests to dashboard etc
Can you show the response headers of these?
specifically ones related to cookies or CSRF
that one


after restarting app and first request
when i click the button where getSeconds gets eventually invoked
then i get a token
but only at the second time
no
only at the first time

all following request dont have a token?

what if i just generate a iput hidden with the token in the get request?
yeah that's how cookies work
the server sends a response with a Set-Cookie header and the browser saves the cookie
Is the user already logged in for the
/dashboard
request?and the server sends it because spring security is on and this: .csrf(csrf -> csrf.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()))
?
yeah pretty much
though without it, it would send it as well but with a different configuration that doesn't allow aceessing it via JS
user must first log in to see /dashboard
so the request to /dashboard is authenticated?
yes with oath2
and /dashboard doesn't set the cookie?
I assume /dashboard is a Spring endpoint as well?
yes
@GetMapping("/dashboard")
public String index(Model model) {
model.addAttribute("activeModulList", modulService.findByActiveStatus(true));
model.addAttribute("deactivatedModulList", modulService.findByActiveStatus(false));
return "home";
}
ok then it's weird that that endpoint doesn't seemt to set the cookie
Can you show the full security config?
btw if you use 3 backticks before and after, it will be formatter better
should it or do i need new Cookie?
Am I correct in the following:
- The response to the request to /dashboard (the one with status 200, not the one with 302!) doesn't have any cookie information
- The response to the next request does have cookie information
no request to /dashboard has cookie info
Can you try something like that? https://stackoverflow.com/a/74813159/10871900
Stack Overflow
Spring Security not sending CSRF token in REST Application
I'm new to Spring Security and I'm trying to understand the CSRF mechanism. I have a Spring based application with Angular. As far as I know, Spring will send a CSRF Token in a cookie on the first ...
so
omg it worked
alternatively you could try the other approach
awesome thanks man REALLY appreciate your help and time
If you are finished with your post, please close it.
If you are not, please ignore this message.
Note that you will not be able to send further messages here after this post have been closed but you will be able to create new posts.
also thank to you and thank your for your time
np
and another option would be to explicitly include the CSRF token in the dashboard response
but if your current approach works, I think that's fine
what was the problem btw
Two things
- Using the wrong header name
- Spring doesn't include CSRF token headers in every response by default - they had to enable that
see the SO answer I linked above for the second point
okok
and also the docs linked in the SO answer
np
Post Closed
This post has been closed by <@653351602983272459>.