라이브러리를 사용하지 않고 자바 스크립트에서 JWT 토큰을 디코딩하는 방법은 무엇입니까?


209

JavaScript를 사용하여 JWT의 페이로드를 어떻게 디코딩 할 수 있습니까? 도서관없이 따라서 토큰은 내 프론트 엔드 앱에서 사용할 수있는 페이로드 객체를 반환합니다.

토큰 예 : xxxxxxxxx.XXXXXXXX.xxxxxxxx

그리고 결과는 페이로드입니다.

{exp: 10012016 name: john doe, scope:['admin']}

1
어떻게 인코딩 되었습니까? 그냥 반대로 해 공유 비밀이 필요합니다.
Lucky Soni

PHP 라이브러리를 사용하는 백엔드 API로 인코딩되었습니다. 여기에 base64를 사용하여 인코딩 된 페이로드가 필요합니다.
Chrisk8er

1
jwt.io 웹 사이트로 이동하여 제공되는 JavaScript 라이브러리를 얻을 수 있습니다.
Quentin

12
이 질문에 약간의 트래픽이 있기 때문에 고지 사항을 추가하고 싶습니다. 서명의 유효성을 검사하지 않고 토큰의 페이로드를 맹목적으로 해독하면 보안 문제가 발생할 수 있습니다! 이 stackoverflow 질문에 제공된 코드를 맹목적으로 사용하기 전에 보안 아키텍처를 이해해야합니다.
Carsten Hoffmann

4
@CarstenHoffmann 그리고 서명을 정확히 어떻게 확인합니까 ??
Saurabh Tiwari

답변:


468

유니 코드 텍스트 작업 JWT 파서 기능 :

function parseJwt (token) {
    var base64Url = token.split('.')[1];
    var base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
    var jsonPayload = decodeURIComponent(atob(base64).split('').map(function(c) {
        return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
    }).join(''));

    return JSON.parse(jsonPayload);
};

2
불행히도 이것은 유니 코드 텍스트에서 작동하지 않는 것 같습니다.
Paul McMahon

2
이 솔루션은 Postman (테스트 탭)에서도 사용할 수 있으며 추가 라이브러리 설치가 필요하지 않습니다. 인증 토큰에서 사용자 ID를 추출하는 데 사용했습니다.
Wlad

2
참고 : 우편 배달부에서 "창"을 제거 JSON.parse(window.atob(base64))해야 작동했습니다. 그냥 return JSON.parse(atob(base64));다음 postman.setEnvironmentVariable("userId", parseJwt(jsonData.access_token)); "access_token이"응답에서의 토큰 값의 키 (귀하의 경우와 다를 수 있습니다) 내 경우입니다.
Wlad

12
위의 솔루션은 토큰의 첫 번째 "-"와 "_"(나에게 고통을 일으키는 자바 스크립트 "기능") 만 대체합니다. 답변의 세 번째 줄을 다음과 같이 바꾸십시오.var base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
Racing Tadpole

2
jwt-decode모듈은 작지만 조금 더 잘 처리하기 때문에 모듈 을 사용 하는 것이 좋습니다.
Rantiev


47

jwt-decode 사용할 수 있으므로 다음과 같이 작성할 수 있습니다.

import jwt_decode from 'jwt-decode';

var token = 'eyJ0eXAiO.../// jwt token';

var decoded = jwt_decode(token);
console.log(decoded);
/*{exp: 10012016 name: john doe, scope:['admin']}*/

67
"도서관이 없다는 뜻입니다."
SherloxTV

이 라이브러리에 문제가 있습니다. 주로 파이어 폭스를 사용합니다. 내가 겪은 문제는 로그 아웃 또는 만료로 인해 token == null 인 경우; 이것은 오류로 페이지를 죽입니다.
LUser

1
@ApertureSecurity이 오류를 잡을 필요가 있지만, 이것이 내가이 라이브러리를 사용하고 싶지 않은 이유입니다.
Luke Robertson

이것은 GZIP를 지원하지 않는 것 같습니다. 사실, 클레임에 GZIP를 지원하는 JS 라이브러리를 찾을 수 없습니다.
앤드류 T 피넬

18

순수 자바 스크립트 atob()함수를 사용 하여 토큰을 문자열로 디코딩 할 수 있습니다 .

atob(token.split('.')[1]);

또는 json 객체로 직접 구문 분석하십시오.

JSON.parse(atob(token.split('.')[1]));

Javascript 함수에 대한 읽기 atob()btoa()기본 제공 Base64 인코딩 및 디코딩-웹 API | MDN .


9

@Peheje는 작동하지만 유니 코드에 문제가 있습니다. 그것을 고치기 위해 https://stackoverflow.com/a/30106551/5277071 의 코드를 사용합니다 .

let b64DecodeUnicode = str =>
  decodeURIComponent(
    Array.prototype.map.call(atob(str), c =>
      '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2)
    ).join(''))

let parseJwt = token =>
  JSON.parse(
    b64DecodeUnicode(
      token.split('.')[1].replace('-', '+').replace('_', '/')
    )
  )


let form = document.getElementById("form")
form.addEventListener("submit", (e) => {
   form.out.value = JSON.stringify(
      parseJwt(form.jwt.value)
   )
   e.preventDefault();
})
textarea{width:300px; height:60px; display:block}
<form id="form" action="parse">
  <textarea name="jwt">eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkrDtGhuIETDs8OoIiwiYWRtaW4iOnRydWV9.469tBeJmYLERjlKi9u6gylb-2NsjHLC_6kZNdtoOGsA</textarea>
  <textarea name="out"></textarea>
  <input type="submit" value="parse" />
</form>


+1이지만 Peheje의 답변에 대한 Tadpole의 레이싱 의견이 맞다면 (바꾸기 호출은 첫 번째 인스턴스 만 바꿉니다), 여기에도 동일한 수정 사항이 적용됩니다.
게리 맥길

9

nodejs 환경에는 "window"객체가 없으므로 다음 코드 줄을 사용할 수 있습니다.

let base64Url = token.split('.')[1]; // token you get
let base64 = base64Url.replace('-', '+').replace('_', '/');
let decodedData = JSON.parse(Buffer.from(base64, 'base64').toString('binary'));

완벽하게 작동합니다. 도움이 되길 바랍니다.


1
노드 js
ireshan pathirana에

7
function parseJwt(token) {
  var base64Payload = token.split('.')[1];
  var payload = Buffer.from(base64Payload, 'base64');
  return JSON.parse(payload);
}
let payload= parseJwt("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c");
console.log("payload:- ", payload);

노드를 사용하는 경우 버퍼 패키지를 사용해야 할 수도 있습니다.

npm install buffer
var Buffer = require('buffer/').Buffer

6

이 함수를 사용 하여이 답변을 기반으로 payload, header, exp (Expiration Time), iat (Issued At)을 얻습니다.

function parseJwt(token) {
  try {
    // Get Token Header
    const base64HeaderUrl = token.split('.')[0];
    const base64Header = base64HeaderUrl.replace('-', '+').replace('_', '/');
    const headerData = JSON.parse(window.atob(base64Header));

    // Get Token payload and date's
    const base64Url = token.split('.')[1];
    const base64 = base64Url.replace('-', '+').replace('_', '/');
    const dataJWT = JSON.parse(window.atob(base64));
    dataJWT.header = headerData;

// TODO: add expiration at check ...


    return dataJWT;
  } catch (err) {
    return false;
  }
}

const jwtDecoded = parseJwt('YOUR_TOKEN') ;
if(jwtDecoded)
{
    console.log(jwtDecoded)
}

이 답변은 다소 나아지지만 2.5 문제가 있습니다. 먼저 서명을 확인하지 않습니다 (배열 항목 2). 둘째, REPLACE는 정규식에서 "g"플래그를 놓치기 때문에 올바르게 작동하지 않습니다 (Rapid Tadpole이 다른 게시물에 댓글을 달았 듯이 JWT에서-및 _의 첫 번째 항목 만 대체합니다). 그리고 절반 : 배열 항목 0과 1을 디코딩하기 위해 전체 코드를 복제하는 대신 FOR 루프를 사용할 수 있습니다 (짧은 코드이지만 SPLIT이 두 번 실행되는 것처럼 더 효율적으로 만들 수 있습니다) ).
사이버 나이트

4

jwt.io의 모든 기능이 모든 언어를 지원하지는 않습니다. NodeJ에서 사용할 수 있습니다

var decoded = jwt.decode(token);

1
라이브러리가 없으면 토큰의 두 번째 부분에서 base64 디코딩을 수행합니다. {var payload = token.split ( '.') [1]); } 그런 다음 base64 디코딩을 수행합니다. {var decodedData = atob (payload); }
Jithin Vijayan

4

jwt.io 에서이 코드를 찾았 으며 잘 작동합니다.

//this is used to parse base64
function url_base64_decode(str) {
  var output = str.replace(/-/g, '+').replace(/_/g, '/');
  switch (output.length % 4) {
    case 0:
      break;
    case 2:
      output += '==';
      break;
    case 3:
      output += '=';
      break;
    default:
      throw 'Illegal base64url string!';
  }
  var result = window.atob(output); //polifyll https://github.com/davidchambers/Base64.js
  try{
    return decodeURIComponent(escape(result));
  } catch (err) {
    return result;
  }
}

어떤 경우에는 (확실한 개발 플랫폼),
가장 좋은 대답은 현재로서는 유효하지 않은 base64 길이의 문제에 직면합니다.
그래서 더 안정적인 방법이 필요했습니다.

도움이 되길 바랍니다.


2

Guy와 Peheje는 이미이 질문에 대답했습니다. 나와 같은 초보자에게는 예제에서 가져 오기 줄을 정의하는 것이 도움이되었습니다.

또한 토큰이 다시 게시되는 전체 자격 증명 세트 (IDToken 부분이 아닌 전체 JWT 토큰)임을 알아내는 데 몇 분이 걸렸습니다. 일단 알면 간단합니다 ..

import jwt_decode from 'jwt-decode';

var token = 'eyJ0eXAiO.../// jwt token';
var decoded = jwt_decode(token);

/*{exp: 10012016 name: john doe, scope:['admin']}*/


2
OP가 요청한 것과 반대되는 다른 사용자와 똑같은 답변을 게시하는 것은 큰 도움이되지 않습니다
Cacoon

2

JSON 웹 토큰 (JWT) 디코딩을위한 간단한 NodeJS 솔루션

function decodeTokenComponent(value) {
    const buff = new Buffer(value, 'base64')
    const text = buff.toString('ascii')
    return JSON.parse(text)
}

const token = 'xxxxxxxxx.XXXXXXXX.xxxxxxxx'
const [headerEncoded, payloadEncoded, signature] = token.split('.')
const [header, payload] = [headerEncoded, payloadEncoded].map(decodeTokenComponent)

console.log(`header: ${header}`)
console.log(`payload: ${payload}`)
console.log(`signature: ${signature}`)

2

답변은 GitHub-auth0 / jwt-decode를 기반으로 합니다. 문자열 분할 및 반환 객체 {header, payload, signature}를 포함하도록 입력 / 출력을 변경하여 전체 토큰을 전달할 수 있습니다.

var jwtDecode = function (jwt) {

        function b64DecodeUnicode(str) {
            return decodeURIComponent(atob(str).replace(/(.)/g, function (m, p) {
                var code = p.charCodeAt(0).toString(16).toUpperCase();
                if (code.length < 2) {
                    code = '0' + code;
                }
                return '%' + code;
            }));
        }

        function decode(str) {
            var output = str.replace(/-/g, "+").replace(/_/g, "/");
            switch (output.length % 4) {
                case 0:
                    break;
                case 2:
                    output += "==";
                    break;
                case 3:
                    output += "=";
                    break;
                default:
                    throw "Illegal base64url string!";
            }

            try {
                return b64DecodeUnicode(output);
            } catch (err) {
                return atob(output);
            }
        }

        var jwtArray = jwt.split('.');

        return {
            header: decode(jwtArray[0]),
            payload: decode(jwtArray[1]),
            signature: decode(jwtArray[2])
        };

    };

1

이 질문을 연구 한 후에 방금 만든 기능이 풍부한 솔루션은 다음과 같습니다.

const parseJwt = (token) => {
    try {
        if (!token) {
            throw new Error('parseJwt# Token is required.');
        }

        const base64Payload = token.split('.')[1];
        let payload = new Uint8Array();

        try {
            payload = Buffer.from(base64Payload, 'base64');
        } catch (err) {
            throw new Error(`parseJwt# Malformed token: ${err}`);
        }

        return {
            decodedToken: JSON.parse(payload),
        };
    } catch (err) {
        console.log(`Bonus logging: ${err}`);

        return {
            error: 'Unable to decode token.',
        };
    }
};

다음은 일부 사용법 샘플입니다.

const unhappy_path1 = parseJwt('sk4u7vgbis4ewku7gvtybrose4ui7gvtmalformedtoken');
console.log('unhappy_path1', unhappy_path1);

const unhappy_path2 = parseJwt('sk4u7vgbis4ewku7gvtybrose4ui7gvt.malformedtoken');
console.log('unhappy_path2', unhappy_path2);

const unhappy_path3 = parseJwt();
console.log('unhappy_path3', unhappy_path3);

const { error, decodedToken } = parseJwt('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c');
if (!decodedToken.exp) {
    console.log('almost_happy_path: token has illegal claims (missing expires_at timestamp)', decodedToken);
    // note: exp, iat, iss, jti, nbf, prv, sub
}

StackOverflow 코드 스 니펫 도구에서 실행할 수 없었지만 다음은 해당 코드를 실행했을 때 볼 수있는 내용입니다.

여기에 이미지 설명을 입력하십시오

parseJwt함수가 항상 객체를 (정적 입력의 이유로 어느 정도) 반환하도록 만들었습니다 .

이를 통해 다음과 같은 구문을 활용할 수 있습니다.

const { decodedToken, error } = parseJwt(token);

그런 다음 런타임에 특정 유형의 오류를 테스트하고 이름 충돌을 피할 수 있습니다.

누구나이 코드에 대한 노력이 적고 가치가 변경되는 것을 생각할 수 있다면의 이익을 위해 내 답변을 자유롭게 편집하십시오 next(person).


0

여기와 여기 에 대한 답변을 바탕으로 :

const dashRE = /-/g;
const lodashRE = /_/g;

module.exports = function jwtDecode(tokenStr) {
  const base64Url = tokenStr.split('.')[1];
  if (base64Url === undefined) return null;
  const base64 = base64Url.replace(dashRE, '+').replace(lodashRE, '/');
  const jsonStr = Buffer.from(base64, 'base64').toString();
  return JSON.parse(jsonStr);
};

-1

Javascript node.js express를 실행하면 먼저 다음과 같이 패키지를 설치해야했습니다.

npm install jwt-decode --save

그런 다음 app.js 코드에서 패키지를 가져옵니다.

const jwt_decode = require('jwt-decode');

그런 다음 코드를 실행하십시오.

let jwt_decoded = jwt_decode(jwt_source);

그런 다음 마술 :

console.log('sub:',jwt_decoded.sub);

4
"도서관을 사용하지 않고"를 기억하십시오
Olaf

1
알았어. 그러나 같은 문제에 직면하여 라이브러리를 사용할 수 없다는 제한이 없었습니다. 이것은 나를 위해 일했습니다. 다른 사람이 비슷한 문제에 직면하고 동일한 제한이 없기 때문에 게시 한 상태로 둡니다.
David White
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.