JSON Web Tokens의 구현입니다.
이는 draft-ietf-oauth-json-web-token-08
를 기반으로 개발되었습니다. node-jws
를 사용합니다.
$ npm install jsonwebtoken
jwt.sign(payload, secretOrPrivateKey, [options, callback])
(비동기식) 콜백이 제공되면, 콜백은 err
또는 JWT
로 호출됩니다.
(동기식) JsonWebToken
을 문자열로 반환합니다.
payload
는 유효한 JSON
을 나타내는 객체 리터럴, 버퍼 또는 문자열일 수 있습니다.참고하세요:
exp
또는 기타 클레임은payload
가 객체 리터럴일 때만 설정됩니다. 버퍼나 문자열 페이로드는JSON
유효성을 검사하지 않습니다.
payload
가 버퍼나 문자열이 아닌 경우, JSON.stringify
를 사용하여 문자열로 강제 변환됩니다.
secretOrPrivateKey
는 HMAC
알고리즘의 비밀 또는 RSA
및 ECDSA
의 PEM
인코딩된 개인 키를 포함하는 문자열 (utf-8
인코딩), 버퍼, 개체 또는 KeyObject
일 수 있습니다. 패스워드가 있는 개인 키의 경우 객체 { key, passphrase }
를 사용할 수 있습니다(기반 crypto
문서), 이 경우 algorithm
옵션을 전달해야합니다.
RSA
알고리즘으로 서명할 때 최소 모듈러스 길이는 2048
입니다. allowInsecureKeySizes
옵션이 true
로 설정되어 있지 않은 경우 이 길이 이하의 개인 키는 오류로 거부됩니다.
options:
algorithm
(기본값: HS256)expiresIn
: 초 단위 또는 시간 간격을 나타내는 문자열 vercel/ms.예: 60, "2 days", "10h", "7d". 숫자 값은 초를 나타냅니다. 문자열을 사용하는 경우 시간 단위(일, 시간 등)를 반드시 제공해야 합니다. 그렇지 않으면 기본적으로 밀리초 단위가 사용됩니다("120"은 "120ms"와 같습니다).
audience
issuer
jwtid
subject
noTimestamp
header
keyid
mutatePayload: true
로 설정하면, sign
함수는 페이로드 개체를 직접 수정합니다. 이것은 페이로드에 대해 클레임이 적용되지만 토큰으로 인코딩되기 전에 원시 참조가 필요한 경우에 유용합니다.allowInsecureKeySizes: true
로 설정하면 RSA
에 대해 모듈러스 길이가 2048
미만인 개인 키를 사용할 수 있습니다.allowInvalidAsymmetricKeyTypes: true
로 설정하면 지정된 알고리즘과 일치하지 않는 비대칭 키를 허용합니다. 이 옵션은 역호환성을 위해 만들어졌으며 피하는 것이 좋습니다.expiresIn
, notBefore
, audience
, subject
, issuer
에 대한 기본값은 없습니다. 이러한 클레임은 exp
, nbf
, aud
, sub
및 iss
를 사용하여 페이로드에 직접 제공할 수 있지만, 두 곳에 동시에 포함할 수는 없습니다.
exp
,nbf
및 iat는 NumericDate입니다. 관련된 Token Expiration (exp claim)를 참조하세요.
헤더는 options.header
개체를 통해 사용자 정의할 수 있습니다.
생성된 jwts
는 noTimestamp
가 지정되지 않은 경우 기본적으로 iat
(발행 시간) 클레임이 포함됩니다. iat
이 페이로드에 삽입된 경우, options.expiresIn
의 시간 간격을 주어진 경우 exp를
계산하는 데 실제 타임스탬프 대신에 사용됩니다.
var jwt = require('jsonwebtoken');
var token = jwt.sign({ foo: 'bar' }, 'shhhhh');
// sign with RSA SHA256
var privateKey = fs.readFileSync('private.key');
var token = jwt.sign({ foo: 'bar' }, privateKey, { algorithm: 'RS256' });
jwt.sign(
{ foo: 'bar' },
privateKey,
{ algorithm: 'RS256' },
function (err, token) {
console.log(token);
}
);
var older_token = jwt.sign(
{ foo: 'bar', iat: Math.floor(Date.now() / 1000) - 30 },
'shhhhh'
);
JWT
의 표준은 만료를 나타내는 exp
클레임을 정의합니다. 만료는 NumericDate
로 표시됩니다.
UTC
기준 1970-01-01T00:00:00Z
부터 지정된 UTC
날짜/시간까지의 초 수를 나타내는 JSON 숫자 값입니다. 윤초를 무시합니다. 이는 IEEE Std 1003.1, 2013 Edition [POSIX.1]
정의인 "Epoch
이후 초 단위"와 동일하며, 각 날은 정확히 86400
초로 계산됩니다. 그 외의 경우 비정수 값을 나타낼 수 있습니다. 자세한 내용은 RFC 3339 [RFC3339]를 참조하십시오.
즉, exp
필드는 epoch
이후의 초 수를 포함해야합니다.
jwt.sign(
{
exp: Math.floor(Date.now() / 1000) + 60 * 60,
data: 'foobar',
},
'secret'
);
이 라이브러리로 이러한 토큰을 생성하는 또 다른 방법은 다음과 같습니다.
jwt.sign(
{
data: 'foobar',
},
'secret',
{ expiresIn: 60 * 60 }
);
// 또는 더 좋은 방법으로:
jwt.sign(
{
data: 'foobar',
},
'secret',
{ expiresIn: '1h' }
);
(비동기적) 콜백을 제공하면 함수가 비동기적으로 작동합니다. 서명이 유효하고 선택적 만료, 청중 또는 발급자가 유효한 경우 디코딩 된 페이로드로 콜백이 호출됩니다. 그렇지 않으면 오류가 발생합니다.
(동기적) 콜백이 제공되지 않은 경우 함수는 동기적으로 작동합니다. 시그니처가 유효하고 선택적으로 만료, 대상 청중 또는 발급자가 유효한 경우 디코딩된 payload를 반환합니다. 그렇지 않으면 오류를 throw합니다.
경고: 토큰이 믿을 수 없는 소스(예: 사용자 입력 또는 외부 요청)에서 가져온 경우, 반환된 디코딩된 payload는 다른 사용자 입력과 마찬가지로 처리해야합니다. 적절한 값만 필터링하고 작업해야합니다.
token
은 JsonWebToken
문자열입니다.
secretOrPublicKey
은 HMAC
알고리즘의 비밀 또는 RSA
및 ECDSA
를 위한 PEM
으로 인코딩 된 공개 키를 포함하는 문자열(UTF-8
인코딩), 버퍼 또는 KeyObject
입니다.
jwt.verify
가 비동기식으로 호출되면 secretOrPublicKey
은 비밀 또는 공개 키를 가져올 함수가 될 수 있습니다. 자세한 예는 아래를 참조하십시오.
이 댓글에서 언급했듯이, 기타 라이브러리에서는 base64
로 인코딩 된 시크릿(랜덤 바이트를 base64
로 인코딩한 것)을 요구하는 경우, Buffer.from
(secret
, 'base64
')를 전달할 수 있습니다. 이렇게하면 시크릿은 base64
로 디코딩되고 토큰 검증은 원래의 랜덤 바이트를 사용합니다.
options
algorithms
: 허용된 알고리즘 이름 목록을 나열한 문자열입니다. 예를 들어 ["HS256", "HS384"]
.지정하지 않으면 제공된 키 유형에 따라 기본값이 사용됩니다.
secret - ['HS256', 'HS384', 'HS512']
rsa - ['RS256', 'RS384', 'RS512']
ec - ['ES256', 'ES384', 'ES512']
기본값 - ['RS256', 'RS384', 'RS512']
audience
: 대상 청중 (aud)을 확인하려면 여기에 값을 제공하십시오. 대상 청중은 문자열, 정규 표현식 또는 문자열 및/또는 정규 표현식 목록으로 확인할 수 있습니다.예:
"urn:foo"
,/urn:f[o]{2}/
,[/urn:f[o]{2}/, "urn:bar"]
complete
: 페이로드, 헤더 및 서명의 디코딩 된 { payload, header, signature } 객체를 반환하려면 일반적인 페이로드 내용만 반환하는 대신 여기에 값을 제공하십시오.issuer
(선택 사항) : iss 필드의 유효한 값의 문자열 또는 문자열 배열입니다.jwtid
(선택 사항): JWT ID (jti)를 확인하려면 여기에 문자열 값을 제공하십시오.ignoreExpiration
: true이면 토큰의 만료를 검증하지 않습니다.ignoreNotBefore
...subject
: 여기서 주제 (sub)를 확인하려면 값을 제공하십시오.clockTolerance
: 서로 다른 서버 간의 작은 시계 차이를 처리하기 위해 nbf 및 exp 클레임을 확인할 때 허용되는 초 수입니다.maxAge
: 토큰이 여전히 유효한 최대 허용 연령입니다. 초 또는 시간 간격을 나타내는 문자열로 표시됩니다. vercel/ms
을 참조하십시오.1000
, "2 days"
, "10h"
, "7d"
. 숫자 값은 초 카운트로 해석됩니다. 문자열을 사용하는 경우 시간 단위(일, 시간 등)를 반드시 제공해야 합니다. 그렇지 않으면 기본적으로 밀리초 단위가 사용됩니다 ("120"
은 "120ms"
와 동일합니다).clockTimestamp
: 필요한 모든 비교에 대해 현재 시간으로 사용해야 하는 초 단위의 시간입니다.
nonce
: 여기서 nonce
클레임을 확인하려면 문자열 값을 제공하십시오. Open ID
에서 ID
토큰에 사용됩니다. (Open ID implementation notes)
-allowInvalidAsymmetricKeyTypes
: true
이면 지정된 알고리즘과 일치하지 않는 비대칭 키가 허용됩니다. 이 옵션은 역 호환성을 위해 사용됩니다. 지양하는 것이 좋습니다.
// 대칭 토큰 확인 - 동기식
var decoded = jwt.verify(token, 'shhhhh');
console.log(decoded.foo); // bar
// 대칭 토큰 확인
jwt.verify(token, 'shhhhh', function (err, decoded) {
console.log(decoded.foo); // bar
});
// 유효하지 않은 토큰 - 동기식
try {
var decoded = jwt.verify(token, 'wrong-secret');
} catch (err) {
// err
}
// 유효하지 않은 토큰
jwt.verify(token, 'wrong-secret', function (err, decoded) {
// err
// decoded undefined
});
// 비대칭 토큰 확인
var cert = fs.readFileSync('public.pem'); // 공개 키 가져오기
jwt.verify(token, cert, function (err, decoded) {
console.log(decoded.foo); // bar
});
// 청중 확인
var cert = fs.readFileSync('public.pem'); // 공개 키 가져오기
jwt.verify(token, cert, { audience: 'urn:foo' }, function (err, decoded) {
// 청중 불일치, err == invalid audience
});
// 발행자 확인
var cert = fs.readFileSync('public.pem'); // 공개 키 가져오기
jwt.verify(
token,
cert,
{ audience: 'urn:foo', issuer: 'urn:issuer' },
function (err, decoded) {
// 발행자 불일치, err == invalid issuer
}
);
// jwt id 확인
var cert = fs.readFileSync('public.pem'); // 공개 키 가져오기
jwt.verify(
token,
cert,
{ audience: 'urn:foo', issuer: 'urn:issuer', jwtid: 'jwtid' },
function (err, decoded) {
// jwt id 불일치, err == invalid jwt id
}
);
// 주제 확인
var cert = fs.readFileSync('public.pem'); // 공개 키 가져오기
jwt.verify(
token,
cert,
{
audience: 'urn:foo',
issuer: 'urn:issuer',
jwtid: 'jwtid',
subject: 'subject',
},
function (err, decoded) {
// 주제 불일치, err == invalid subject
}
);
// 알고리즘 불일치
var cert = fs.readFileSync('public.pem'); // 공개 키 가져오기
jwt.verify(token, cert, { algorithms: ['RS256'] }, function (err, payload) {
// 토큰 알고리즘이 RS256이 아닌 경우, err == invalid signature
});
// getKey 콜백을 사용하여 확인
// 예제는 https://github.com/auth0/node-jwks-rsa 를 사용하여 키를 가져오는 방법을 보여줍니다.
var jwksClient = require('jwks-rsa');
var client = jwksClient({
jwksUri: 'https://sandrino.auth0.com/.well-known/jwks.json',
});
function getKey(header, callback) {
client.getSigningKey(header.kid, function (err, key) {
var signingKey = key.publicKey || key.rsaPublicKey;
callback(null, signingKey);
});
}
jwt.verify(token, getKey, options, function (err, decoded) {
console.log(decoded.foo); // bar
})
(동기적) 시그니처가 유효한지 확인하지 않고 디코딩된 payload
를 반환합니다.
경고: 이 함수는 시그니처가 유효한지 검증하지 않습니다. 신뢰할 수 없는 메시지에는 사용하지 마십시오. 대신 jwt.
verify
를 사용하는 것이 좋습니다.
경고: 토큰이 신뢰할 수 없는 소스(예: 사용자 입력 또는 외부 요청)에서 가져온 경우, 반환된 디코딩된 payload는 다른 사용자 입력과 동일하게 처리되어야 합니다. 예상되는 속성으로만 작업하도록 정리되었는지 확인하십시오.
token
은 JsonWebToken
문자열입니다.
options
:
json
: 헤더가 "typ":"JWT"
를 포함하지 않아도 페이로드에서 JSON.parse
를 강제로 실행합니다.complete
: 디코딩된 페이로드와 헤더를 포함한 객체를 반환합니다.예제
// 시그니처 무시하고 디코딩된 페이로드 가져오기, secretOrPrivateKey가 필요하지 않습니다.
var decoded = jwt.decode(token);
// 디코딩된 페이로드와 헤더 가져오기
var decoded = jwt.decode(token, { complete: true });
console.log(decoded.header);
console.log(decoded.payload);
검증 중 발생 가능한 오류입니다. 오류는 검증 콜백의 첫 번째 인수입니다.
토큰이 만료되었을 때 발생하는 오류입니다.
오류 객체:
name
: 'TokenExpiredError'message
: 'jwt expired'expiredAt
: [ExpDate]jwt.verify(token, 'shhhhh', function (err, decoded) {
if (err) {
/*
err = {
name: 'TokenExpiredError',
message: 'jwt expired',
expiredAt: 1408621000
}
*/
}
});
오류 객체:
jwt.verify(token, 'shhhhh', function (err, decoded) {
if (err) {
/*
err = {
name: 'JsonWebTokenError',
message: 'jwt malformed'
}
*/
}
});
nbf claim에 지정된 시간 이전에 현재 시간이면 발생합니다.
에러 객체:
jwt.verify(token, 'shhhhh', function (err, decoded) {
if (err) {
/*
err = {
name: 'NotBeforeError',
message: 'jwt not active',
date: 2018-10-04T16:10:44.000Z
}
*/
}
});
지원하는 알고리즘의 배열입니다. 현재 다음 알고리즘이 지원됩니다.
alg Parameter Value | Digital Signature or MAC Algorithm |
---|---|
HS256 | HMAC using SHA-256 hash algorithm |
HS384 | HMAC using SHA-384 hash algorithm |
HS512 | HMAC using SHA-512 hash algorithm |
RS256 | RSASSA-PKCS1-v1_5 using SHA-256 hash algorithm |
RS384 | RSASSA-PKCS1-v1_5 using SHA-384 hash algorithm |
RS512 | RSASSA-PKCS1-v1_5 using SHA-512 hash algorithm |
PS256 | RSASSA-PSS using SHA-256 hash algorithm (only node ^6.12.0 OR >=8.0.0) |
PS384 | RSASSA-PSS using SHA-384 hash algorithm (only node ^6.12.0 OR >=8.0.0) |
PS512 | RSASSA-PSS using SHA-512 hash algorithm (only node ^6.12.0 OR >=8.0.0) |
ES256 | ECDSA using P-256 curve and SHA-256 hash algorithm |
ES384 | ECDSA using P-384 curve and SHA-384 hash algorithm |
ES512 | ECDSA using P-521 curve and SHA-512 hash algorithm |
none | No digital signature or MAC value included |
먼저 JWT 자동 재발급이 시스템에 취약점을 도입하지 않는지 신중히 고려하는 것이 좋습니다.
라이브러리의 일부로 이것을 포함하는 것은 편하지 않지만, 이 예제를 살펴보면 이를 어떻게 수행할 수 있는지 알 수 있습니다. 이 외에도 이 주제에 대한 더 많은 지식을 얻을 수 있는 an issue와 a pull request가 있습니다.