1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
|
# frozen_string_literal: true
RSpec.describe JWT::Token do
let(:payload) { { 'pay' => 'load' } }
let(:header) { {} }
subject(:token) { described_class.new(payload: payload, header: header) }
describe '#sign!' do
it 'signs the token' do
token.sign!(algorithm: 'HS256', key: 'secret')
expect(JWT::EncodedToken.new(token.jwt).valid_signature?(algorithm: 'HS256', key: 'secret')).to be(true)
end
context 'when signed twice' do
before do
token.sign!(algorithm: 'HS256', key: 'secret')
end
it 'raises' do
expect { token.sign!(algorithm: 'HS256', key: 'secret') }.to raise_error(JWT::EncodeError)
end
end
context 'when RSA JWK is given as key' do
let(:jwk) { JWT::JWK::RSA.new(OpenSSL::PKey::RSA.new(2048), alg: 'RS256') }
it 'signs the token' do
token.sign!(key: jwk, algorithm: []) # any algorithm is fine here
expect(JWT::EncodedToken.new(token.jwt).valid_signature?(algorithm: 'RS256', key: jwk.verify_key)).to be(true)
end
context 'with algorithm provided in sign call' do
it 'signs the token' do
token.sign!(algorithm: %w[RS256 RS512], key: jwk)
expect(JWT::EncodedToken.new(token.jwt).valid_signature?(algorithm: 'RS256', key: jwk.verify_key)).to be(true)
end
end
context 'with mismatching algorithm provided in sign call' do
it 'signs the token' do
expect { token.sign!(algorithm: %w[RS384 RS512], key: jwk) }.to raise_error(JWT::DecodeError, 'Provided JWKs do not support one of the specified algorithms: RS384, RS512')
end
end
end
context 'when string key is given but not algorithm' do
it 'raises an error' do
expect { token.sign!(key: 'secret') }.to raise_error(ArgumentError, /missing keyword/)
end
end
end
context 'when EC JWK is given as key' do
let(:jwk) { JWT::JWK::EC.new(test_pkey('ec384-private.pem')) }
it 'signs the token' do
token.sign!(key: jwk, algorithm: [])
expect(JWT::EncodedToken.new(token.jwt).valid_signature?(algorithm: [], key: jwk)).to be(true)
end
end
describe '#jwt' do
context 'when token is signed' do
before do
token.sign!(algorithm: 'HS256', key: 'secret')
end
it 'returns a signed and encoded token' do
expect(token.jwt).to eq('eyJhbGciOiJIUzI1NiJ9.eyJwYXkiOiJsb2FkIn0.UEhDY1Qlj29ammxuVRA_-gBah4qTy5FngIWg0yEAlC0')
expect(JWT.decode(token.jwt, 'secret', true, algorithm: 'HS256')).to eq([{ 'pay' => 'load' }, { 'alg' => 'HS256' }])
end
end
context 'when token is not signed' do
it 'returns a signed and encoded token' do
expect { token.jwt }.to raise_error(JWT::EncodeError)
end
end
context 'when alg is given in header' do
let(:header) { { 'alg' => 'HS123' } }
before do
token.sign!(algorithm: 'HS256', key: 'secret')
end
it 'returns a signed and encoded token' do
expect(JWT::EncodedToken.new(token.jwt).header).to eq({ 'alg' => 'HS123' })
end
end
end
describe '#detach_payload!' do
context 'before token is signed' do
it 'detaches the payload' do
token.detach_payload!
token.sign!(algorithm: 'HS256', key: 'secret')
expect(token.jwt).to eq('eyJhbGciOiJIUzI1NiJ9..UEhDY1Qlj29ammxuVRA_-gBah4qTy5FngIWg0yEAlC0')
end
end
end
describe '#verify_claims!' do
context 'when required_claims is passed' do
it 'raises error' do
expect { token.verify_claims!(required: ['exp']) }.to raise_error(JWT::MissingRequiredClaim, 'Missing required claim exp')
end
end
end
describe '#valid_claims?' do
context 'exp claim' do
let(:payload) { { 'exp' => Time.now.to_i - 10, 'pay' => 'load' } }
context 'when claim is valid' do
it 'returns true' do
expect(token.valid_claims?(exp: { leeway: 1000 })).to be(true)
end
end
context 'when claim is invalid' do
it 'returns true' do
expect(token.valid_claims?(:exp)).to be(false)
end
end
end
end
describe '#claim_errors' do
context 'exp claim' do
let(:payload) { { 'exp' => Time.now.to_i - 10, 'pay' => 'load' } }
context 'when claim is valid' do
it 'returns empty array' do
expect(token.claim_errors(exp: { leeway: 1000 })).to be_empty
end
end
context 'when claim is invalid' do
it 'returns array with error objects' do
expect(token.claim_errors(:exp).map(&:message)).to eq(['Signature has expired'])
end
end
end
end
end
|