inflearn logo
강의

Course

Instructor

Building a Chat Platform Using Spring Boot

Running a Service and Testing and Debugging - 2

JWTDecodeException 에러가 나옵니다.

Resolved

144

cloverj0

23 asked

0

알려주신데로 UserControllerV1.java에 어노테이션 추가하고 재기동한 뒤 검색 했는데...로그에

com.auth0.jwt.exceptions.JWTDecodeException: The token was expected to have 3 parts, but got 1.

이런 에러가 나옵니다.ㅠㅠ

개발자 도구에는 아래와 같은 에러가 나옵니다.

image.png

 

UserControllerV1.java는 이렇게 작성되어 있습니다.

image.png

 

어떤 부분을 더 확인해야 하는지, 어떤 부분이 문제 인건지 확인 부탁드립니다.ㅠㅠ

 

**추가로 에러내용 전체입니다.

com.auth0.jwt.exceptions.JWTDecodeException: The token was expected to have 3 parts, but got 1.

at com.auth0.jwt.TokenUtils.splitToken(TokenUtils.java:21)

~[java-jwt-3.12.0.jar!/:3.12.0]

at com.auth0.jwt.JWTDecoder.<init>(JWTDecoder.java:36) ~[java-jwt-3.12.0.jar!/:3.12.0]

at com.auth0.jwt.JWTDecoder.<init>(JWTDecoder.java:32) ~[java-jwt-3.12.0.jar!/:3.12.0]

at com.auth0.jwt.JWT.decode(JWT.java:45) ~[java-jwt-3.12.0.jar!/:3.12.0]

at com.example.demo.security.JWTProvider.decodedJWT(JWTProvider.java:109) ~[!/:0.0.1-SNAPSHOT]

at com.example.demo.security.JWTProvider.getUserFromToken(JWTProvider.java:123) ~[!/:0.0.1-SNAPSHOT]

at com.example.demo.domain.user.controller.UserControllerV1.searchUser(UserControllerV1.java:43) ~[!/:0.0.1-SNAPSHOT]

at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]

at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[na:na]

at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]

at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[na:na]

at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:255) ~[spring-web-6.1.13.jar!/:6.1.13]

at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:188) ~[spring-web-6.1.13.jar!/:6.1.13]

at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:118) ~[spring-webmvc-6.1.13.jar!/:6.1.13]

at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:926) ~[spring-webmvc-6.1.13.jar!/:6.1.13]

at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:831) ~[spring-webmvc-6.1.13.jar!/:6.1.13]

at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-6.1.13.jar!/:6.1.13]

at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1089) ~[spring-webmvc-6.1.13.jar!/:6.1.13]

at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:979) ~[spring-webmvc-6.1.13.jar!/:6.1.13]

at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1014) ~[spring-webmvc-6.1.13.jar!/:6.1.13]

at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:903) ~[spring-webmvc-6.1.13.jar!/:6.1.13]

at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:564) ~[tomcat-embed-core-10.1.30.jar!/:na]

at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:885) ~[spring-webmvc-6.1.13.jar!/:6.1.13]

at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:658) ~[tomcat-embed-core-10.1.30.jar!/:na]

at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:195) ~[tomcat-embed-core-10.1.30.jar!/:na]

at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140) ~[tomcat-embed-core-10.1.30.jar!/:na]

at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51) ~[tomcat-embed-websocket-10.1.30.jar!/:na]

at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164) ~[tomcat-embed-core-10.1.30.jar!/:na]

at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140) ~[tomcat-embed-core-10.1.30.jar!/:na]

at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) ~[spring-web-6.1.13.jar!/:6.1.13]

at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-6.1.13.jar!/:6.1.13]

at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164) ~[tomcat-embed-core-10.1.30.jar!/:na]

at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140) ~[tomcat-embed-core-10.1.30.jar!/:na]

at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) ~[spring-web-6.1.13.jar!/:6.1.13]

at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-6.1.13.jar!/:6.1.13]

at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164) ~[tomcat-embed-core-10.1.30.jar!/:na]

at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140) ~[tomcat-embed-core-10.1.30.jar!/:na]

at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) ~[spring-web-6.1.13.jar!/:6.1.13]

at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-6.1.13.jar!/:6.1.13]

at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164) ~[tomcat-embed-core-10.1.30.jar!/:na]

at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140) ~[tomcat-embed-core-10.1.30.jar!/:na]

at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:167) ~[tomcat-embed-core-10.1.30.jar!/:na]

at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:90) ~[tomcat-embed-core-10.1.30.jar!/:na]

at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:483) ~[tomcat-embed-core-10.1.30.jar!/:na]

at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:115) ~[tomcat-embed-core-10.1.30.jar!/:na]

at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:93) ~[tomcat-embed-core-10.1.30.jar!/:na]

at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74) ~[tomcat-embed-core-10.1.30.jar!/:na]

at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:344) ~[tomcat-embed-core-10.1.30.jar!/:na]

at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:384) ~[tomcat-embed-core-10.1.30.jar!/:na]

at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63) ~[tomcat-embed-core-10.1.30.jar!/:na]

at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:905) ~[tomcat-embed-core-10.1.30.jar!/:na]

at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1741) ~[tomcat-embed-core-10.1.30.jar!/:na]

at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52) ~[tomcat-embed-core-10.1.30.jar!/:na]

at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1190) ~[tomcat-embed-core-10.1.30.jar!/:na]

at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) ~[tomcat-embed-core-10.1.30.jar!/:na]

at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:63) ~[tomcat-embed-core-10.1.30.jar!/:na]

at java.base/java.lang.Thread.run(Thread.java:833) ~[na:na]

mysql spring-boot jpa jwt websocket

Answer 2

0

Hong

안녕하세요 cloverj0님 질문 남겨주셔서 감사합니다.

 

전반적인 에러 문구를 보았을 떄, Authorization 헤더에 값이 이상한거 같습니다.

 

다음과 같은 부분을 확인해보시면 좋을 꺼 같아요.

  1. API에 들어오는 헤더 값

  2. 요청을 하는 API 소스

  3. JwtProvider에서 token을 핸들링 하는 소스

 

1번 과정에 대해서는 기본적인 로그를 찍어보시고 확인해보시면 좋을 꺼 같고

2,3번 과정에 대해서는 소스 제공해 주시면 확인해보도록 하겠습니다.

 

감사합니다!

0

cloverj0

안녕하세요!

 

1번에 알려주신 헤더 값을 찍어보니

=========authString=============Bearer token (헤더부분)

=========token=============token

이렇게 값이 나옵니다! 이 두 값이 나오는 게 맞을까요?

 

소스는

https://github.com/hyunjin-joo/inf_study.git

이곳에 src 폴더를 업로드 해놓았습니다!! 더 확인해 봐야 할 폴더가 있으시면 말씀 부탁드립니다:)

(또는 https://drive.google.com/drive/folders/1Yi7cJpnW360yN9kCoWfTWGe7jYVCEHpb?usp=sharing

여기에서 확인 부탁드립니다! - 몇 개의 파일은 다 업로드가 되지 않아 더 확인해야 할 파일이 있으면 말씀 부탁드립니다!)

 

항상 친절히 답 주셔서 감사합니다!

 

 

0

Hong

음 로그상 저렇게 노출이 된다면, 기본적인 값은 정확하게 들어온거 같습니다.

하지만 에러구문 상에서, JWTDecodeException이 발생하고, 에러 문구는 다음과 같이 발생하고 있습니다.

  • The token was expected to have 3 parts, but got 1.

이 에러는 기본적으로 JWT는 3가지 파트로 구성이 되어 있는데, 디코딩을 진행하니 한가지 파트로만 진행이 되어 있다는 에러 입니다.

 

즉 Token을 잘못생성하여 값을 전달한게 아닐까 싶습니다.

 

우선적으로 사용하시는 Token을 다음과 같은 사이트에서 확인하시고 3가지 파트로 구성이 되어 있는지 확인해보시면 좋을 꺼 같습니다.

 

그리고 만약 문제가 있다면, 토큰을 생성하는 부분이나, Clinet에서 값을 잘라서 보내는지를 확인해봐야 할 꺼 같습니다.

0

cloverj0

안녕하세요!

npm run dev 하는 쪽의 로그를 보니

⨯ src\components\chat\chat-layout.tsx (36:22) @ document

⨯ ReferenceError: document is not defined

at getCookie (./src/components/chat/chat-layout.tsx:26:24)

at useMountEffect (./src/components/chat/chat-layout.tsx:42:28)

at ChatLayout (./src/components/chat/chat-layout.tsx:78:5)

digest: "1286481958"

34 | function getCookie(name: string): string | undefined {

35 |

> 36 | const value = ; ${document.cookie};

| ^

37 | const parts = value.split; ${name}=);

38 | if (parts.length === 2) return parts.pop()?.split(";").shift();

39 | }

GET / 500 in 107ms

GET /.well-known/appspecific/com.chrome.devtools.json 404 in 64ms

 

이런 에러가 나옵니다...처음부터 token값이든 cookie 값이든 가져올 때 잘못 가져와서 그런건가요...? 제 생각에는 처음부터 가져올 때 잘못 작성한 게 있는 것 같아서 이 부분부터 해결해야 할 것 같습니다ㅠㅠ

여기저기 검색해보고 선생님께서 올려주신 소스코드도 보고 하는데 대체 어디가 문제인지 알 수가 없습니다..

 

그리고 한번 로그인 하면 그 뒤로 계속 자동으로 로그인 되는데, 이 부분도 어딜 수정해야 하는지 알려주실 수 있으실까요...?

 

항상 답변 주셔서 감사합니다ㅠㅠ

스승의 날인데 모쪼록 좋은 하루 보내세요!

0

Hong

한번 로그인을 진행을 하게 되면, 브라우저의 쿠키를 저장하게 됩니다.

 

개발자 도구에서 Application 이후 Cookie에서 값을 삭제하면 될 꺼 같습니다.

스크린샷 2025-05-15 오후 11.00.46.png
  • 현재 제 화면인데 해당 화면과 유사하게 접속하셔서 삭제하시면 됩니다.

     

0

Hong

우선 Login 컴포넌트에서

 

useEffect(() => {
    // Client-side cookie access to check if user is already authenticated
    const authCookie = document.cookie
      .split("; ")
      .find((row) => row.startsWith("auth="));
    if (authCookie) {
      router.push("/");
    }
  }, [router]);

  const handleSubmit = async (event: FormEvent) => {
    event.preventDefault();
    // Add login logic here

    const result = await api.post("/api/v1/auth/login", {
      name: username,
      password: password,
    });

    if (!result.data.token) {
      alert("존재하지 않은 User 입니다.");
      return;
    }

    document.cookie = `auth=${result.data.token}; path=/`;
    router.push("/");
  };

 

해당 소스에 들어오는 result.data.token 에 console.log를 찍어서 값을 확인해 봐야 할 꺼 같습니다.

0

cloverj0

안녕하세요! console.log에 찍어봤는데,

const handleSubmit = async (event: FormEvent) => 

이 안에서 찍히지 않는 것을 확인했습니다!! 혹시 따로 다운로드하거나 import 시켜야 할 것이 있는 건가요?

0

Hong

import는 아니고, 추가하신 로그가 정상적인 JWT 포멧인지 jwt.io에 접속해 확인을 해보셔야 할 꺼 같습니다.

0

Hong

에러 문구 자체가 일단 JWT의 일반적인 형태가 아니라는 에러가 발생하고 있어서요

1

cloverj0

안녕하세요! 답이 늦어져서 죄송합니다.

token값을 제가 "token"으로 넣는 바람에 그대로 "token"으로 들어가서 해당 에러가 나온 것 같습니다ㅠㅠ(그래서 해결되었습니다ㅎ)

정말..친절히 답 주셔서 감사합니다!!

0

communityai8509

안녕하세요, 인프런 AI 인턴입니다. cloverj0님.

JWTDecodeException 에러는 보통 JWT 토큰의 형식이 올바르지 않을 때 발생합니다. JWT 토큰은 일반적으로 header.payload.signature 형태로 이루어져 있어야 합니다. 에러 메시지에 따르면, 토큰이 예상하는 3개의 파트를 포함하고 있지 않음을 의미합니다. 이 문제는 다양한 원인으로 발생할 수 있으며, 다음과 같은 부분을 확인해 보세요.

1. 토큰 형식 확인

  • 먼저, 서버 쪽에서 실제 저장된 JWT 토큰의 형식이 올바른지 확인해보세요. 가끔 잘못된 값이 저장되거나 파싱될 때 문제가 생길 수 있습니다.

2. 토큰 발급 부분 확인

  • 토큰을 처음 생성하는 부분에서 올바르게 생성되었는지 재확인하세요. 토큰 생성시 header, payload, signature를 올바르게 설정되었는지 점검해 주세요.

3. Authorization 헤더 값

  • UserControllerV1Authorization 헤더에서 JWT 토큰을 올바르게 추출하고 있는지 확인하세요. JWT는 Bearer 접두사 없이 순수한 토큰 문자열이어야 합니다.

4. 디버깅 로그 추가

  • searchUser 메서드 실행 전후로 디버깅 로그를 추가하여 토큰 값이 어떻게 처리되고 있는지 확인해 보세요. 이렇게 하면 문제가 발생하는 시점을 더 자세히 파악할 수 있습니다.

JWT 관련한 문제를 해결하는데 도움이 될 수 있는 다음 자료도 참고해 보세요:
- JWT 토큰 형식과 구조 이해하기
- Spring Security와 JWT 통합 시 발생할 수 있는 일반적인 에러 해결

위의 내용을 참고하여 문제를 해결하시길 바랍니다. 제가 제공한 링크들은 유사한 문제 해결에 도움이 될 수 있으며, 추가적으로 궁금하신 점이 있으면 언제든지 질문해 주세요. 곧 지식공유자께서도 도움을 주실 것입니다.

저는 질문자님의 이해를 돕고자 지식공유자님의 기존 답변을 참고하여 유사한 답변 링크를 추천해드리고 있습니다. 현재 베타 기능으로 답변이 만족스럽지 않을 수 있는 점 양해 부탁드립니다. 🙏

추가적으로 궁금한 점이 있으시면, 이어서 질문해 주세요. 곧 지식공유자께서 답변해 주실 것입니다.

패키지 구분에 대해 궁금한게 있습니다

0

7

1

스프링부트 서버 에러나요

0

17

1

코드를 첨부해야하는 이유가 있나요?

0

20

2

74. 데이터 캐시 - 1 (이론) 강의 영상 누락

0

26

1

2026.04에 추가된 강의 시청 불가

0

27

1

비전공자인데 AI가 발전한 요즘 백엔드로 진로를 하고 싶으면 어떤식으로 공부를 해야 하는지 알 수 있을까요???

0

60

1

STOMP에서 메세지를 전송하는 방법에 대해

0

89

1

서비스 구동하며 테스트와 디버깅하기 - 1 에서 기동하는 방법

0

118

2

MySQLConfig 관련 질문있습니다.

0

168

2

ChatListResponse에 @Valid을 붙인 이유

0

133

2

checkTokenForRefresh에 대해 궁금한점

0

112

2

Client 파일은 어떤 IDE로 실행시키나요??

0

188

2

독립적인 Transactional을 둔 이유

2

140

2

springdoc이 무슨 설정인가요??

1

120

2

JwtProvider 를 Component 로 선언하신 이유가 궁금합니다.

0

199

2

안녕하세요 연관관계에 대해 질문이 있습니다.

0

143

2

안녕하세요 MySqlConfig 설정에 대해 질문이 있습니다.

0

125

2

MySQL을 미리 설정을 해놔야할까요?

0

174

3

./gradlew clean build 하면 오류가 생깁니다.

0

1176

2

작동하는 방법

0

175

2

Package 구성

0

145

2

@Transactional(transactionManager = "createChatTransacationMansger") 질문 있습니다.

0

182

2

강의 들으면서 블로그에 올려도 될까요?

0

181

2

실 서비스 환경 문의

1

261

2