{"id":16541341,"url":"https://github.com/itzg/try-nextjs-jwt-boot-api","last_synced_at":"2025-03-04T04:41:34.595Z","repository":{"id":40928481,"uuid":"242445669","full_name":"itzg/try-nextjs-jwt-boot-api","owner":"itzg","description":"Next.js web application that uses JWT issued by Auth0 to access authenticated Spring Boot API","archived":false,"fork":false,"pushed_at":"2023-10-24T22:48:48.000Z","size":643,"stargazers_count":1,"open_issues_count":2,"forks_count":0,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-01-14T08:52:13.465Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/itzg.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-02-23T02:48:32.000Z","updated_at":"2023-03-13T12:54:55.000Z","dependencies_parsed_at":"2025-01-14T08:43:27.349Z","dependency_job_id":"949ce63d-1339-4da2-be58-2d18201038c2","html_url":"https://github.com/itzg/try-nextjs-jwt-boot-api","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/itzg%2Ftry-nextjs-jwt-boot-api","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/itzg%2Ftry-nextjs-jwt-boot-api/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/itzg%2Ftry-nextjs-jwt-boot-api/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/itzg%2Ftry-nextjs-jwt-boot-api/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/itzg","download_url":"https://codeload.github.com/itzg/try-nextjs-jwt-boot-api/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":241787488,"owners_count":20020099,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-11T18:54:44.135Z","updated_at":"2025-03-04T04:41:34.574Z","avatar_url":"https://github.com/itzg.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"Next.js web application that uses JWT issued by Auth0 to access authenticated Spring Boot API\n\n## Setup\n\nIn the `src/main/app` directory create an `.env` file with the following variables populated from your Auth0 application config:\n\n```\nAUTH0_DOMAIN=...\nAUTH0_CLIENT_ID=...\nAUTH0_CLIENT_SECRET=...\nBASE_URL=http://localhost:3000\nAUTH0_COOKIE_SECRET=...\n```\n\n## Running\n\nStart the api/backend, replace `YOURS` with your Auth0 subdomain:\n```\nmvn spring-boot:run -Dspring-boot.run.jvmArguments=\"-Dauth0-subdomain=YOURS\"\n```\n\nStart the frontend:\n```\nmvn frontend:npm@run-frontend\n```\n\n## Implementation Notes\n\n### Solving `401 Unauthorized` during CORS preflight in Spring Webflux\n\nThe `CorsConfigurationSource` in `WebConfig` is needed to fully configure CORS support in Spring Webflux. Without it, the `fetch` initiated from the browser \n\n```javascript\n    const res = await fetch('http://localhost:8080/api/greeting', {\n      headers: {\n        Authorization: `Bearer ${idToken}`\n      }\n    });\n```\n\nwill fail with this error shown in the browser console:\n\n```\nAccess to fetch at 'http://localhost:8080/api/greeting' from origin 'http://localhost:3000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.\n```\n\nWith the Spring property `logging.level.web=debug`, the application logs provide a clue about why the CORS preflight failed:\n\n```\no.s.w.s.adapter.HttpWebHandlerAdapter    : [599fe63a] HTTP OPTIONS \"/api/greeting\"\no.s.w.s.adapter.HttpWebHandlerAdapter    : [599fe63a] Completed 401 UNAUTHORIZED\n```\n\nThe reason it results in a 401 is two-fold:\n- The `OPTIONS` request of the [CORS preflight](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#Preflighted_requests) purposely limits the headers included, especially the `Authorization` header. It is actually the CORS response from the server that will indicate such headers are allowed.\n- So it's a catch-22 at preflight time...without the authorization header, Spring Security will fail the `OPTIONS` request to a protected path, `/api/greeting` in this case.\n\nCORS registration via an implementation of `addCorsMappings` in `WebFluxConfigurer` doesn't seem to activate the CORS filter creation. Instead, [the `CorsWebFilter` creation within `ServerHttpSecurity.CorsSpec.getCorsFilter`](https://github.com/spring-projects/spring-security/blob/f2da2c56bef17b686450f31d7ef3fb71bcbd85a1/config/src/main/java/org/springframework/security/config/web/server/ServerHttpSecurity.java#L659) activates when a `CorsConfigurationSource` bean is present.\n\nThe following is a quick and overly permissive configuration that satisfies the filter creation. It is important to declare `Authorization` as an allowed header; otherwise, the browser will vaguely report the same CORS preflight failure since it knows the original fetch operation could not be executed without it.\n\n```java\n  @Bean\n  public CorsConfigurationSource corsConfigurationSource() {\n    CorsConfiguration corsConfig = new CorsConfiguration();\n    corsConfig.addAllowedOrigin(CorsConfiguration.ALL);\n    corsConfig.addAllowedMethod(CorsConfiguration.ALL);\n    corsConfig.addAllowedHeader(\"Authorization\");\n\n    final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();\n    source.registerCorsConfiguration(\"/api/**\", corsConfig);\n\n    return source;\n  }\n```\n\nThe Network tab of Chrome DevTools doesn't show the preflight details, so for the curious, here are the interesting bits of the CORS preflight for this particular application.\n\nThe request:\n```\nOPTIONS /api/greeting HTTP/1.1\nHost: localhost:8080\nAccess-Control-Request-Method: GET\nAccess-Control-Request-Headers: authorization\nOrigin: http://localhost:3000\nSec-Fetch-Mode: cors\nSec-Fetch-Site: same-site\n```\n\n...and the response from Spring CORS processing:\n```\nHTTP/1.1 200 OK\nAccess-Control-Allow-Origin: *\nAccess-Control-Allow-Methods: GET\nAccess-Control-Allow-Headers: authorization\n```","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fitzg%2Ftry-nextjs-jwt-boot-api","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fitzg%2Ftry-nextjs-jwt-boot-api","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fitzg%2Ftry-nextjs-jwt-boot-api/lists"}