pub struct Token<P, State: MaybeSigned = Unsigned<()>, Fmt: TokenFormat = Compact> { /* private fields */ }Expand description
A JSON web token, generic over the signing state, format, and payload.
Tokens can change state using the sign, verify, and unverify methods.
The format can generally not be changed after constructing the token.
JAWS does not support the general JWS format, only the compact format and the flat format.
§Examples
A few examples are shown below, but the most powerful examples are shown
in the examples directory.
§Creating a compact token
use jaws::token::Token;
let token = Token::compact((), ());This token will have no payload, and no custom headers.
To view a debug representation of the token, use the fmt::JWTFormat trait:
use jaws::fmt::JWTFormat;
println!("{}", token.formatted());§Transitioning a token between states
Tokens start in either the Unsigned or Unverified state. Unsigned tokens
are ones constructed locally, but before a signature has been applied. Unverified
tokens are ones which have been parsed from a string, but which have not yet been
checked.
To transition a token from the Unsigned state to the Signed state, use the
Token::sign method:
let key = rsa::pkcs1v15::SigningKey::random(&mut rand::OsRng, 2048).unwrap();
let token = Token::compact((), ());
// The only way to get a signed token is to sign an Unsigned token!
let signed = token.sign::<rsa::pkcs1v15::SigningKey<sha2::Sha256>, rsa::pkcs1v15::Signature>(&key).unwrap();
println!("Token: {}", signed.rendered().unwrap());Signing often requires specifying the algorithm to use. In the example above, we use
RS256, which is the RSA-PKCS1-v1-5 signature algorithm with SHA-256. The algorithm is
specified by constraining the type of key when calling Token::sign.
Signed tokens can become unverified ones by discarding the memory of the key used to sign
them. This is done with the Token::unverify method:
// We can unverify the token, which discard the memory of the key used to sign it.
let unverified = signed.unverify();
// Unverified tokens still have a signature, but it is no longer considered valid.
println!("Token: {}", unverified.rendered().unwrap());Tokens can also be transitioned from the Unverified state to the Verified state
by checking the signature. This is done with the Token::verify method:
let verified = unverified.verify::<_, rsa::pkcs1v15::Signature>(&verifying_key).unwrap();
println!("Token: {}", verified.rendered().unwrap());Verification can fail if the signature is invalid, or if the algorithm does not match the one specified in the header. Since keys are strongly typed, it is not possible to make a signature substitution attack using a different key type.
Implementations§
Source§impl<P, H, Fmt> Token<P, Unsigned<H>, Fmt>where
Fmt: TokenFormat,
impl<P, H, Fmt> Token<P, Unsigned<H>, Fmt>where
Fmt: TokenFormat,
Sourcepub fn new(header: H, payload: P, fmt: Fmt) -> Self
pub fn new(header: H, payload: P, fmt: Fmt) -> Self
Create a new token with the given header and payload, in a given format.
See also Token::compact and Token::flat to create a token in a specific format.
Examples found in repository?
36fn main() {
37 // This key is from RFC 7515, Appendix A.2. Provide your own key instead!
38 // The key here is stored as a PKCS#8 PEM file, but you can leverage
39 // RustCrypto to load a variety of other formats.
40 let key = rsa::RsaPrivateKey::from_pkcs8_pem(include_str!(concat!(
41 env!("CARGO_MANIFEST_DIR"),
42 "/examples/rfc7515a2.pem"
43 )))
44 .unwrap();
45
46 // We will sign the JWT with the RS256 algorithm: RSA with SHA-256.
47 // RsaPkcs1v15 is really an alias to the digital signature algorithm
48 // implementation in the `rsa` crate, but provided in JAWS to make
49 // it clear which types are compatible with JWTs.
50 let alg = rsa::pkcs1v15::SigningKey::<Sha256>::new(key);
51
52 let payload = json!({
53 "termsOfServiceAgreed": true,
54 "contact": [
55 "mailto:cert-admin@example.org",
56 "mailto:admin@example.org"
57 ]
58 });
59
60 let header = json!({
61 "nonce": "6S8IqOGY7eL2lsGoTZYifg",
62 "url": "https://example.com/acme/new-account"
63 });
64
65 // Create a token with the default headers, and no custom headers.
66 let mut token = Token::new(payload, header, Compact);
67 // Request that the token header include a JWK field.
68 token.header_mut().key().derived();
69
70 // Sign the token with the algorithm and key we specified above.
71 let signed = token.sign::<_, rsa::pkcs1v15::Signature>(&alg).unwrap();
72
73 // Print the token in the ACME example format.
74 println!("{}", signed.formatted());
75}Source§impl<P, Fmt> Token<P, Unsigned<()>, Fmt>where
Fmt: TokenFormat,
impl<P, Fmt> Token<P, Unsigned<()>, Fmt>where
Fmt: TokenFormat,
Sourcepub fn new_with_payload(payload: P, fmt: Fmt) -> Self
pub fn new_with_payload(payload: P, fmt: Fmt) -> Self
Create a token with a given payload and format, but no custom header values.
Source§impl<P, H> Token<P, Unsigned<H>, Compact>
impl<P, H> Token<P, Unsigned<H>, Compact>
Sourcepub fn compact(header: H, payload: P) -> Token<P, Unsigned<H>, Compact>
pub fn compact(header: H, payload: P) -> Token<P, Unsigned<H>, Compact>
Create a new token with the given header and payload, in the compact format.
See also Token::new and Token::flat to create a token in a specific format.
The compact format is the format with base64url encoded header and payload, separated by a dot, and with the signature appended.
Examples found in repository?
49fn unsigned_token() -> Token<Unsigned<()>> {
50 let claims = Claims {
51 registered: RegisteredClaims {
52 subject: "1234567890".to_string().into(),
53 ..Default::default()
54 },
55 claims: json!({
56 "name": "John Doe",
57 "admin": true,
58 }),
59 };
60
61 let mut token = Token::compact((), claims);
62 *token.header_mut().r#type() = Some("JWT".to_string());
63 token.header_mut().key().derived();
64 token
65}More examples
36fn main() -> Result<(), Box<dyn std::error::Error>> {
37 // This key is from RFC 7515, Appendix A.2. Provide your own key instead!
38 // The key here is stored as a PKCS#8 PEM file, but you can leverage
39 // RustCrypto to load a variety of other formats.
40 let key = rsa::RsaPrivateKey::from_pkcs8_pem(include_str!(concat!(
41 env!("CARGO_MANIFEST_DIR"),
42 "/examples/rfc7515a2.pem"
43 )))
44 .unwrap();
45
46 // We will sign the JWT with the RS256 algorithm: RSA with SHA-256.
47 let alg = rsa::pkcs1v15::SigningKey::<Sha256>::new(key);
48
49 // Claims can combine registered and custom fields. The claims object
50 // can be any type which implements [serde::Serialize].
51 let claims: Claims<serde_json::Value, (), String, (), ()> = Claims {
52 registered: RegisteredClaims {
53 subject: "1234567890".to_string().into(),
54 ..Default::default()
55 },
56 claims: json!({
57 "name": "John Doe",
58 "admin": true,
59 }),
60 };
61
62 // Create a token with the default headers, and no custom headers.
63 // The unit type can be used here because it implements [serde::Serialize],
64 // but a custom type could be passed if we wanted to have custom header
65 // fields.
66 let mut token = Token::compact((), claims);
67
68 // We can modify the headers freely before signing the JWT. In this case,
69 // we provide the `typ` header, which is optional in the JWT spec.
70 *token.header_mut().r#type() = Some("JWT".to_string());
71
72 // We can also ask that some fields be derived from the signing key, for example,
73 // this will derive the JWK field in the header from the signing key.
74 token.header_mut().key().derived();
75
76 println!("=== Initial JWT ===");
77 // Initially the JWT has no defined signature:
78 println!("{}", token.formatted());
79
80 // Sign the token with the algorithm, and print the result.
81 let signed = token.sign::<_, rsa::pkcs1v15::Signature>(&alg).unwrap();
82
83 println!("=== Signed JWT ===");
84
85 println!("JWT:");
86 println!("{}", signed.formatted());
87 println!("Token: {}", signed.rendered().unwrap());
88
89 // We can't modify the token after signing it (that would change the signature)
90 // but we can access fields and read from them:
91 println!(
92 "Type: {:?}, Algorithm: {:?}",
93 signed.header().r#type(),
94 signed.header().algorithm(),
95 );
96
97 // We can also verify tokens.
98 let token: Token<Claims<serde_json::Value>, Unverified<()>, Compact> =
99 signed.rendered().unwrap().parse().unwrap();
100
101 println!("=== Parsed JWT ===");
102
103 // Unverified tokens can be printed for debugging, but there is deliberately
104 // no access to the payload, only to the header fields.
105 println!("JWT:");
106 println!("{}", token.formatted());
107
108 // We can use the JWK to verify that the token is signed with the correct key.
109 let hdr = token.header();
110 let jwk = hdr.key().unwrap();
111 let key = rsa::RsaPublicKey::from_jwk(jwk).unwrap();
112
113 assert_eq!(&key, alg.verifying_key().as_ref());
114 println!("=== Verification === ");
115 let alg: rsa::pkcs1v15::VerifyingKey<Sha256> = alg.verifying_key();
116
117 // We can't access the claims until we verify the token.
118 let verified = token
119 .verify::<_, jaws::algorithms::SignatureBytes>(&alg)
120 .unwrap();
121
122 println!("=== Verified JWT ===");
123 println!("JWT:");
124 println!("{}", verified.formatted());
125 println!(
126 "Payload: \n{}",
127 serde_json::to_string_pretty(&verified.payload()).unwrap()
128 );
129
130 Ok(())
131}18fn main() -> Result<(), Box<dyn std::error::Error>> {
19 // This key is from RFC 7515, Appendix A.2. Provide your own key instead!
20 // The key here is stored as a PKCS#8 PEM file, but you can leverage
21 // RustCrypto to load a variety of other formats.
22 let signing_key = rsa::RsaPrivateKey::from_pkcs8_pem(include_str!(concat!(
23 env!("CARGO_MANIFEST_DIR"),
24 "/examples/rfc7515a2.pem"
25 )))
26 .unwrap();
27 let verify_key: rsa::pkcs1v15::VerifyingKey<Sha256> =
28 rsa::pkcs1v15::VerifyingKey::new(signing_key.to_public_key());
29
30 // We will sign the JWT with a type-erased algorithm, and use a type-erased
31 // verifier to verify it. This allows you to use a set of verifiers which
32 // are not known at compile time.
33 let dyn_signing_key: Box<dyn TokenSigner<SignatureBytes>> = Box::new(
34 rsa::pkcs1v15::SigningKey::<Sha256>::new(signing_key.clone()),
35 );
36 let dyn_verify_key: Box<dyn TokenVerifier<SignatureBytes>> = Box::new(verify_key.clone());
37
38 // Claims can combine registered and custom fields. The claims object
39 // can be any type which implements [serde::Serialize].
40 let claims: Claims<serde_json::Value, (), String, (), ()> = Claims {
41 registered: RegisteredClaims {
42 subject: "1234567890".to_string().into(),
43 ..Default::default()
44 },
45 claims: json!({
46 "name": "John Doe",
47 "admin": true,
48 }),
49 };
50
51 // Create a token with the default headers, and no custom headers.
52 // The unit type can be used here because it implements [serde::Serialize],
53 // but a custom type could be passed if we wanted to have custom header
54 // fields.
55 let mut token = Token::compact((), claims);
56 // We can modify the headers freely before signing the JWT. In this case,
57 // we provide the `typ` header, which is optional in the JWT spec.
58 *token.header_mut().r#type() = Some("JWT".to_string());
59
60 // We can also ask that some fields be derived from the signing key, for example,
61 // this will derive the JWK field in the header from the signing key.
62 token.header_mut().key().derived();
63
64 println!("=== Initial JWT ===");
65
66 // Initially the JWT has no defined signature:
67 println!("{}", token.formatted());
68
69 // Sign the token with the algorithm, and print the result.
70 let signed = token
71 .sign::<_, SignatureBytes>(dyn_signing_key.as_ref())
72 .unwrap();
73
74 let rendered = signed.rendered().unwrap();
75
76 // We can also verify tokens.
77 let token: Token<Claims<serde_json::Value>, Unverified<()>, Compact> =
78 rendered.parse().unwrap();
79
80 println!("=== Parsed JWT ===");
81
82 // Unverified tokens can be printed for debugging, but there is deliberately
83 // no access to the payload, only to the header fields.
84 println!("JWT:");
85 println!("{}", token.formatted());
86
87 // We can use the JWK to verify that the token is signed with the correct key.
88 let hdr = token.header();
89 let jwk = hdr.key().unwrap();
90 let key: rsa::pkcs1v15::VerifyingKey<Sha256> =
91 rsa::pkcs1v15::VerifyingKey::new(rsa::RsaPublicKey::from_jwk(jwk).unwrap());
92
93 println!("=== Verification === ");
94 // Check it against the verified key
95 token
96 .clone()
97 .verify::<_, rsa::pkcs1v15::Signature>(&verify_key)
98 .unwrap();
99 println!(
100 "Verified with verify key (typed): {}",
101 type_name_of_val(&verify_key)
102 );
103
104 // Check it against the verified key
105 let verified = token
106 .clone()
107 .verify::<_, SignatureBytes>(dyn_verify_key.as_ref())
108 .unwrap();
109 println!(
110 "Verified with dyn verify key: {}",
111 type_name_of_val(&dyn_verify_key)
112 );
113
114 // Check it against its own JWT
115 token
116 .clone()
117 .verify::<_, rsa::pkcs1v15::Signature>(&key)
118 .unwrap();
119 println!("Verified with JWK");
120
121 println!("=== Verified JWT ===");
122 println!("JWT:");
123 println!("{}", verified.formatted());
124 println!(
125 "Payload: \n{}",
126 serde_json::to_string_pretty(&verified.payload()).unwrap()
127 );
128
129 Ok(())
130}Source§impl<P, H> Token<P, Unsigned<H>, Flat>
impl<P, H> Token<P, Unsigned<H>, Flat>
Sourcepub fn flat(header: H, payload: P) -> Token<P, Unsigned<H>, Flat>
pub fn flat(header: H, payload: P) -> Token<P, Unsigned<H>, Flat>
Create a new token with the given header and payload, in the flat format.
See also Token::new and Token::compact to create a token in a specific format.
The flat format is the format with a JSON object containing the header, payload, and
signature, all in the same object. It can also include additional JSON data as “unprotected”
headers, which are not signed and cannot be verified.
Source§impl<P, State: MaybeSigned, Fmt: TokenFormat> Token<P, State, Fmt>
impl<P, State: MaybeSigned, Fmt: TokenFormat> Token<P, State, Fmt>
Sourcepub fn header(&self) -> HeaderAccess<'_, State::Header, State::HeaderState>
pub fn header(&self) -> HeaderAccess<'_, State::Header, State::HeaderState>
Access to Token header values.
All access is read-only, and the header cannot be modified here,
see Token::header_mut for mutable access.
Header fields are accessed as methods on HeaderAccess, and
their types will depend on the state of the token. Additionally,
the alg field will not be availalbe for unsigned token types.
§Example: No custom headers, only registered headers.
use jaws::token::Token;
let token = Token::compact((), ());
let header = token.header();
assert_eq!(&header.r#type(), &None);Examples found in repository?
36fn main() -> Result<(), Box<dyn std::error::Error>> {
37 // This key is from RFC 7515, Appendix A.2. Provide your own key instead!
38 // The key here is stored as a PKCS#8 PEM file, but you can leverage
39 // RustCrypto to load a variety of other formats.
40 let key = rsa::RsaPrivateKey::from_pkcs8_pem(include_str!(concat!(
41 env!("CARGO_MANIFEST_DIR"),
42 "/examples/rfc7515a2.pem"
43 )))
44 .unwrap();
45
46 // We will sign the JWT with the RS256 algorithm: RSA with SHA-256.
47 let alg = rsa::pkcs1v15::SigningKey::<Sha256>::new(key);
48
49 // Claims can combine registered and custom fields. The claims object
50 // can be any type which implements [serde::Serialize].
51 let claims: Claims<serde_json::Value, (), String, (), ()> = Claims {
52 registered: RegisteredClaims {
53 subject: "1234567890".to_string().into(),
54 ..Default::default()
55 },
56 claims: json!({
57 "name": "John Doe",
58 "admin": true,
59 }),
60 };
61
62 // Create a token with the default headers, and no custom headers.
63 // The unit type can be used here because it implements [serde::Serialize],
64 // but a custom type could be passed if we wanted to have custom header
65 // fields.
66 let mut token = Token::compact((), claims);
67
68 // We can modify the headers freely before signing the JWT. In this case,
69 // we provide the `typ` header, which is optional in the JWT spec.
70 *token.header_mut().r#type() = Some("JWT".to_string());
71
72 // We can also ask that some fields be derived from the signing key, for example,
73 // this will derive the JWK field in the header from the signing key.
74 token.header_mut().key().derived();
75
76 println!("=== Initial JWT ===");
77 // Initially the JWT has no defined signature:
78 println!("{}", token.formatted());
79
80 // Sign the token with the algorithm, and print the result.
81 let signed = token.sign::<_, rsa::pkcs1v15::Signature>(&alg).unwrap();
82
83 println!("=== Signed JWT ===");
84
85 println!("JWT:");
86 println!("{}", signed.formatted());
87 println!("Token: {}", signed.rendered().unwrap());
88
89 // We can't modify the token after signing it (that would change the signature)
90 // but we can access fields and read from them:
91 println!(
92 "Type: {:?}, Algorithm: {:?}",
93 signed.header().r#type(),
94 signed.header().algorithm(),
95 );
96
97 // We can also verify tokens.
98 let token: Token<Claims<serde_json::Value>, Unverified<()>, Compact> =
99 signed.rendered().unwrap().parse().unwrap();
100
101 println!("=== Parsed JWT ===");
102
103 // Unverified tokens can be printed for debugging, but there is deliberately
104 // no access to the payload, only to the header fields.
105 println!("JWT:");
106 println!("{}", token.formatted());
107
108 // We can use the JWK to verify that the token is signed with the correct key.
109 let hdr = token.header();
110 let jwk = hdr.key().unwrap();
111 let key = rsa::RsaPublicKey::from_jwk(jwk).unwrap();
112
113 assert_eq!(&key, alg.verifying_key().as_ref());
114 println!("=== Verification === ");
115 let alg: rsa::pkcs1v15::VerifyingKey<Sha256> = alg.verifying_key();
116
117 // We can't access the claims until we verify the token.
118 let verified = token
119 .verify::<_, jaws::algorithms::SignatureBytes>(&alg)
120 .unwrap();
121
122 println!("=== Verified JWT ===");
123 println!("JWT:");
124 println!("{}", verified.formatted());
125 println!(
126 "Payload: \n{}",
127 serde_json::to_string_pretty(&verified.payload()).unwrap()
128 );
129
130 Ok(())
131}More examples
18fn main() -> Result<(), Box<dyn std::error::Error>> {
19 // This key is from RFC 7515, Appendix A.2. Provide your own key instead!
20 // The key here is stored as a PKCS#8 PEM file, but you can leverage
21 // RustCrypto to load a variety of other formats.
22 let signing_key = rsa::RsaPrivateKey::from_pkcs8_pem(include_str!(concat!(
23 env!("CARGO_MANIFEST_DIR"),
24 "/examples/rfc7515a2.pem"
25 )))
26 .unwrap();
27 let verify_key: rsa::pkcs1v15::VerifyingKey<Sha256> =
28 rsa::pkcs1v15::VerifyingKey::new(signing_key.to_public_key());
29
30 // We will sign the JWT with a type-erased algorithm, and use a type-erased
31 // verifier to verify it. This allows you to use a set of verifiers which
32 // are not known at compile time.
33 let dyn_signing_key: Box<dyn TokenSigner<SignatureBytes>> = Box::new(
34 rsa::pkcs1v15::SigningKey::<Sha256>::new(signing_key.clone()),
35 );
36 let dyn_verify_key: Box<dyn TokenVerifier<SignatureBytes>> = Box::new(verify_key.clone());
37
38 // Claims can combine registered and custom fields. The claims object
39 // can be any type which implements [serde::Serialize].
40 let claims: Claims<serde_json::Value, (), String, (), ()> = Claims {
41 registered: RegisteredClaims {
42 subject: "1234567890".to_string().into(),
43 ..Default::default()
44 },
45 claims: json!({
46 "name": "John Doe",
47 "admin": true,
48 }),
49 };
50
51 // Create a token with the default headers, and no custom headers.
52 // The unit type can be used here because it implements [serde::Serialize],
53 // but a custom type could be passed if we wanted to have custom header
54 // fields.
55 let mut token = Token::compact((), claims);
56 // We can modify the headers freely before signing the JWT. In this case,
57 // we provide the `typ` header, which is optional in the JWT spec.
58 *token.header_mut().r#type() = Some("JWT".to_string());
59
60 // We can also ask that some fields be derived from the signing key, for example,
61 // this will derive the JWK field in the header from the signing key.
62 token.header_mut().key().derived();
63
64 println!("=== Initial JWT ===");
65
66 // Initially the JWT has no defined signature:
67 println!("{}", token.formatted());
68
69 // Sign the token with the algorithm, and print the result.
70 let signed = token
71 .sign::<_, SignatureBytes>(dyn_signing_key.as_ref())
72 .unwrap();
73
74 let rendered = signed.rendered().unwrap();
75
76 // We can also verify tokens.
77 let token: Token<Claims<serde_json::Value>, Unverified<()>, Compact> =
78 rendered.parse().unwrap();
79
80 println!("=== Parsed JWT ===");
81
82 // Unverified tokens can be printed for debugging, but there is deliberately
83 // no access to the payload, only to the header fields.
84 println!("JWT:");
85 println!("{}", token.formatted());
86
87 // We can use the JWK to verify that the token is signed with the correct key.
88 let hdr = token.header();
89 let jwk = hdr.key().unwrap();
90 let key: rsa::pkcs1v15::VerifyingKey<Sha256> =
91 rsa::pkcs1v15::VerifyingKey::new(rsa::RsaPublicKey::from_jwk(jwk).unwrap());
92
93 println!("=== Verification === ");
94 // Check it against the verified key
95 token
96 .clone()
97 .verify::<_, rsa::pkcs1v15::Signature>(&verify_key)
98 .unwrap();
99 println!(
100 "Verified with verify key (typed): {}",
101 type_name_of_val(&verify_key)
102 );
103
104 // Check it against the verified key
105 let verified = token
106 .clone()
107 .verify::<_, SignatureBytes>(dyn_verify_key.as_ref())
108 .unwrap();
109 println!(
110 "Verified with dyn verify key: {}",
111 type_name_of_val(&dyn_verify_key)
112 );
113
114 // Check it against its own JWT
115 token
116 .clone()
117 .verify::<_, rsa::pkcs1v15::Signature>(&key)
118 .unwrap();
119 println!("Verified with JWK");
120
121 println!("=== Verified JWT ===");
122 println!("JWT:");
123 println!("{}", verified.formatted());
124 println!(
125 "Payload: \n{}",
126 serde_json::to_string_pretty(&verified.payload()).unwrap()
127 );
128
129 Ok(())
130}Source§impl<P, H, Fmt: TokenFormat> Token<P, Unsigned<H>, Fmt>
impl<P, H, Fmt: TokenFormat> Token<P, Unsigned<H>, Fmt>
Sourcepub fn header_mut(&mut self) -> HeaderAccessMut<'_, H, UnsignedHeader>
pub fn header_mut(&mut self) -> HeaderAccessMut<'_, H, UnsignedHeader>
Mutable access to Token header values
Examples found in repository?
49fn unsigned_token() -> Token<Unsigned<()>> {
50 let claims = Claims {
51 registered: RegisteredClaims {
52 subject: "1234567890".to_string().into(),
53 ..Default::default()
54 },
55 claims: json!({
56 "name": "John Doe",
57 "admin": true,
58 }),
59 };
60
61 let mut token = Token::compact((), claims);
62 *token.header_mut().r#type() = Some("JWT".to_string());
63 token.header_mut().key().derived();
64 token
65}More examples
36fn main() {
37 // This key is from RFC 7515, Appendix A.2. Provide your own key instead!
38 // The key here is stored as a PKCS#8 PEM file, but you can leverage
39 // RustCrypto to load a variety of other formats.
40 let key = rsa::RsaPrivateKey::from_pkcs8_pem(include_str!(concat!(
41 env!("CARGO_MANIFEST_DIR"),
42 "/examples/rfc7515a2.pem"
43 )))
44 .unwrap();
45
46 // We will sign the JWT with the RS256 algorithm: RSA with SHA-256.
47 // RsaPkcs1v15 is really an alias to the digital signature algorithm
48 // implementation in the `rsa` crate, but provided in JAWS to make
49 // it clear which types are compatible with JWTs.
50 let alg = rsa::pkcs1v15::SigningKey::<Sha256>::new(key);
51
52 let payload = json!({
53 "termsOfServiceAgreed": true,
54 "contact": [
55 "mailto:cert-admin@example.org",
56 "mailto:admin@example.org"
57 ]
58 });
59
60 let header = json!({
61 "nonce": "6S8IqOGY7eL2lsGoTZYifg",
62 "url": "https://example.com/acme/new-account"
63 });
64
65 // Create a token with the default headers, and no custom headers.
66 let mut token = Token::new(payload, header, Compact);
67 // Request that the token header include a JWK field.
68 token.header_mut().key().derived();
69
70 // Sign the token with the algorithm and key we specified above.
71 let signed = token.sign::<_, rsa::pkcs1v15::Signature>(&alg).unwrap();
72
73 // Print the token in the ACME example format.
74 println!("{}", signed.formatted());
75}36fn main() -> Result<(), Box<dyn std::error::Error>> {
37 // This key is from RFC 7515, Appendix A.2. Provide your own key instead!
38 // The key here is stored as a PKCS#8 PEM file, but you can leverage
39 // RustCrypto to load a variety of other formats.
40 let key = rsa::RsaPrivateKey::from_pkcs8_pem(include_str!(concat!(
41 env!("CARGO_MANIFEST_DIR"),
42 "/examples/rfc7515a2.pem"
43 )))
44 .unwrap();
45
46 // We will sign the JWT with the RS256 algorithm: RSA with SHA-256.
47 let alg = rsa::pkcs1v15::SigningKey::<Sha256>::new(key);
48
49 // Claims can combine registered and custom fields. The claims object
50 // can be any type which implements [serde::Serialize].
51 let claims: Claims<serde_json::Value, (), String, (), ()> = Claims {
52 registered: RegisteredClaims {
53 subject: "1234567890".to_string().into(),
54 ..Default::default()
55 },
56 claims: json!({
57 "name": "John Doe",
58 "admin": true,
59 }),
60 };
61
62 // Create a token with the default headers, and no custom headers.
63 // The unit type can be used here because it implements [serde::Serialize],
64 // but a custom type could be passed if we wanted to have custom header
65 // fields.
66 let mut token = Token::compact((), claims);
67
68 // We can modify the headers freely before signing the JWT. In this case,
69 // we provide the `typ` header, which is optional in the JWT spec.
70 *token.header_mut().r#type() = Some("JWT".to_string());
71
72 // We can also ask that some fields be derived from the signing key, for example,
73 // this will derive the JWK field in the header from the signing key.
74 token.header_mut().key().derived();
75
76 println!("=== Initial JWT ===");
77 // Initially the JWT has no defined signature:
78 println!("{}", token.formatted());
79
80 // Sign the token with the algorithm, and print the result.
81 let signed = token.sign::<_, rsa::pkcs1v15::Signature>(&alg).unwrap();
82
83 println!("=== Signed JWT ===");
84
85 println!("JWT:");
86 println!("{}", signed.formatted());
87 println!("Token: {}", signed.rendered().unwrap());
88
89 // We can't modify the token after signing it (that would change the signature)
90 // but we can access fields and read from them:
91 println!(
92 "Type: {:?}, Algorithm: {:?}",
93 signed.header().r#type(),
94 signed.header().algorithm(),
95 );
96
97 // We can also verify tokens.
98 let token: Token<Claims<serde_json::Value>, Unverified<()>, Compact> =
99 signed.rendered().unwrap().parse().unwrap();
100
101 println!("=== Parsed JWT ===");
102
103 // Unverified tokens can be printed for debugging, but there is deliberately
104 // no access to the payload, only to the header fields.
105 println!("JWT:");
106 println!("{}", token.formatted());
107
108 // We can use the JWK to verify that the token is signed with the correct key.
109 let hdr = token.header();
110 let jwk = hdr.key().unwrap();
111 let key = rsa::RsaPublicKey::from_jwk(jwk).unwrap();
112
113 assert_eq!(&key, alg.verifying_key().as_ref());
114 println!("=== Verification === ");
115 let alg: rsa::pkcs1v15::VerifyingKey<Sha256> = alg.verifying_key();
116
117 // We can't access the claims until we verify the token.
118 let verified = token
119 .verify::<_, jaws::algorithms::SignatureBytes>(&alg)
120 .unwrap();
121
122 println!("=== Verified JWT ===");
123 println!("JWT:");
124 println!("{}", verified.formatted());
125 println!(
126 "Payload: \n{}",
127 serde_json::to_string_pretty(&verified.payload()).unwrap()
128 );
129
130 Ok(())
131}18fn main() -> Result<(), Box<dyn std::error::Error>> {
19 // This key is from RFC 7515, Appendix A.2. Provide your own key instead!
20 // The key here is stored as a PKCS#8 PEM file, but you can leverage
21 // RustCrypto to load a variety of other formats.
22 let signing_key = rsa::RsaPrivateKey::from_pkcs8_pem(include_str!(concat!(
23 env!("CARGO_MANIFEST_DIR"),
24 "/examples/rfc7515a2.pem"
25 )))
26 .unwrap();
27 let verify_key: rsa::pkcs1v15::VerifyingKey<Sha256> =
28 rsa::pkcs1v15::VerifyingKey::new(signing_key.to_public_key());
29
30 // We will sign the JWT with a type-erased algorithm, and use a type-erased
31 // verifier to verify it. This allows you to use a set of verifiers which
32 // are not known at compile time.
33 let dyn_signing_key: Box<dyn TokenSigner<SignatureBytes>> = Box::new(
34 rsa::pkcs1v15::SigningKey::<Sha256>::new(signing_key.clone()),
35 );
36 let dyn_verify_key: Box<dyn TokenVerifier<SignatureBytes>> = Box::new(verify_key.clone());
37
38 // Claims can combine registered and custom fields. The claims object
39 // can be any type which implements [serde::Serialize].
40 let claims: Claims<serde_json::Value, (), String, (), ()> = Claims {
41 registered: RegisteredClaims {
42 subject: "1234567890".to_string().into(),
43 ..Default::default()
44 },
45 claims: json!({
46 "name": "John Doe",
47 "admin": true,
48 }),
49 };
50
51 // Create a token with the default headers, and no custom headers.
52 // The unit type can be used here because it implements [serde::Serialize],
53 // but a custom type could be passed if we wanted to have custom header
54 // fields.
55 let mut token = Token::compact((), claims);
56 // We can modify the headers freely before signing the JWT. In this case,
57 // we provide the `typ` header, which is optional in the JWT spec.
58 *token.header_mut().r#type() = Some("JWT".to_string());
59
60 // We can also ask that some fields be derived from the signing key, for example,
61 // this will derive the JWK field in the header from the signing key.
62 token.header_mut().key().derived();
63
64 println!("=== Initial JWT ===");
65
66 // Initially the JWT has no defined signature:
67 println!("{}", token.formatted());
68
69 // Sign the token with the algorithm, and print the result.
70 let signed = token
71 .sign::<_, SignatureBytes>(dyn_signing_key.as_ref())
72 .unwrap();
73
74 let rendered = signed.rendered().unwrap();
75
76 // We can also verify tokens.
77 let token: Token<Claims<serde_json::Value>, Unverified<()>, Compact> =
78 rendered.parse().unwrap();
79
80 println!("=== Parsed JWT ===");
81
82 // Unverified tokens can be printed for debugging, but there is deliberately
83 // no access to the payload, only to the header fields.
84 println!("JWT:");
85 println!("{}", token.formatted());
86
87 // We can use the JWK to verify that the token is signed with the correct key.
88 let hdr = token.header();
89 let jwk = hdr.key().unwrap();
90 let key: rsa::pkcs1v15::VerifyingKey<Sha256> =
91 rsa::pkcs1v15::VerifyingKey::new(rsa::RsaPublicKey::from_jwk(jwk).unwrap());
92
93 println!("=== Verification === ");
94 // Check it against the verified key
95 token
96 .clone()
97 .verify::<_, rsa::pkcs1v15::Signature>(&verify_key)
98 .unwrap();
99 println!(
100 "Verified with verify key (typed): {}",
101 type_name_of_val(&verify_key)
102 );
103
104 // Check it against the verified key
105 let verified = token
106 .clone()
107 .verify::<_, SignatureBytes>(dyn_verify_key.as_ref())
108 .unwrap();
109 println!(
110 "Verified with dyn verify key: {}",
111 type_name_of_val(&dyn_verify_key)
112 );
113
114 // Check it against its own JWT
115 token
116 .clone()
117 .verify::<_, rsa::pkcs1v15::Signature>(&key)
118 .unwrap();
119 println!("Verified with JWK");
120
121 println!("=== Verified JWT ===");
122 println!("JWT:");
123 println!("{}", verified.formatted());
124 println!(
125 "Payload: \n{}",
126 serde_json::to_string_pretty(&verified.payload()).unwrap()
127 );
128
129 Ok(())
130}Source§impl<P, S, Fmt> Token<P, S, Fmt>where
S: MaybeSigned,
Fmt: TokenFormat,
Token serialization and message packing.
impl<P, S, Fmt> Token<P, S, Fmt>where
S: MaybeSigned,
Fmt: TokenFormat,
Token serialization and message packing.
Sourcepub fn into_format<NewFmt>(self) -> Token<P, S, NewFmt>where
NewFmt: TokenFormat + From<Fmt>,
pub fn into_format<NewFmt>(self) -> Token<P, S, NewFmt>where
NewFmt: TokenFormat + From<Fmt>,
Convert this token to a new format
Sourcepub fn message(&self) -> Result<String, Error>where
P: Serialize,
<S as MaybeSigned>::Header: Serialize,
<S as MaybeSigned>::HeaderState: Serialize + HeaderState,
pub fn message(&self) -> Result<String, Error>where
P: Serialize,
<S as MaybeSigned>::Header: Serialize,
<S as MaybeSigned>::HeaderState: Serialize + HeaderState,
Get the payload and header of the token, serialized in the compact format, suitable as input into a signature algorithm.
Sourcepub fn rendered(&self) -> Result<String, TokenFormattingError>where
P: Serialize,
S: HasSignature,
<S as MaybeSigned>::Header: Serialize,
<S as MaybeSigned>::HeaderState: HeaderState,
pub fn rendered(&self) -> Result<String, TokenFormattingError>where
P: Serialize,
S: HasSignature,
<S as MaybeSigned>::Header: Serialize,
<S as MaybeSigned>::HeaderState: HeaderState,
Get the payload and header of the token, serialized including signature data.
This method is only available when the token is in a signed state.
Examples found in repository?
More examples
36fn main() -> Result<(), Box<dyn std::error::Error>> {
37 // This key is from RFC 7515, Appendix A.2. Provide your own key instead!
38 // The key here is stored as a PKCS#8 PEM file, but you can leverage
39 // RustCrypto to load a variety of other formats.
40 let key = rsa::RsaPrivateKey::from_pkcs8_pem(include_str!(concat!(
41 env!("CARGO_MANIFEST_DIR"),
42 "/examples/rfc7515a2.pem"
43 )))
44 .unwrap();
45
46 // We will sign the JWT with the RS256 algorithm: RSA with SHA-256.
47 let alg = rsa::pkcs1v15::SigningKey::<Sha256>::new(key);
48
49 // Claims can combine registered and custom fields. The claims object
50 // can be any type which implements [serde::Serialize].
51 let claims: Claims<serde_json::Value, (), String, (), ()> = Claims {
52 registered: RegisteredClaims {
53 subject: "1234567890".to_string().into(),
54 ..Default::default()
55 },
56 claims: json!({
57 "name": "John Doe",
58 "admin": true,
59 }),
60 };
61
62 // Create a token with the default headers, and no custom headers.
63 // The unit type can be used here because it implements [serde::Serialize],
64 // but a custom type could be passed if we wanted to have custom header
65 // fields.
66 let mut token = Token::compact((), claims);
67
68 // We can modify the headers freely before signing the JWT. In this case,
69 // we provide the `typ` header, which is optional in the JWT spec.
70 *token.header_mut().r#type() = Some("JWT".to_string());
71
72 // We can also ask that some fields be derived from the signing key, for example,
73 // this will derive the JWK field in the header from the signing key.
74 token.header_mut().key().derived();
75
76 println!("=== Initial JWT ===");
77 // Initially the JWT has no defined signature:
78 println!("{}", token.formatted());
79
80 // Sign the token with the algorithm, and print the result.
81 let signed = token.sign::<_, rsa::pkcs1v15::Signature>(&alg).unwrap();
82
83 println!("=== Signed JWT ===");
84
85 println!("JWT:");
86 println!("{}", signed.formatted());
87 println!("Token: {}", signed.rendered().unwrap());
88
89 // We can't modify the token after signing it (that would change the signature)
90 // but we can access fields and read from them:
91 println!(
92 "Type: {:?}, Algorithm: {:?}",
93 signed.header().r#type(),
94 signed.header().algorithm(),
95 );
96
97 // We can also verify tokens.
98 let token: Token<Claims<serde_json::Value>, Unverified<()>, Compact> =
99 signed.rendered().unwrap().parse().unwrap();
100
101 println!("=== Parsed JWT ===");
102
103 // Unverified tokens can be printed for debugging, but there is deliberately
104 // no access to the payload, only to the header fields.
105 println!("JWT:");
106 println!("{}", token.formatted());
107
108 // We can use the JWK to verify that the token is signed with the correct key.
109 let hdr = token.header();
110 let jwk = hdr.key().unwrap();
111 let key = rsa::RsaPublicKey::from_jwk(jwk).unwrap();
112
113 assert_eq!(&key, alg.verifying_key().as_ref());
114 println!("=== Verification === ");
115 let alg: rsa::pkcs1v15::VerifyingKey<Sha256> = alg.verifying_key();
116
117 // We can't access the claims until we verify the token.
118 let verified = token
119 .verify::<_, jaws::algorithms::SignatureBytes>(&alg)
120 .unwrap();
121
122 println!("=== Verified JWT ===");
123 println!("JWT:");
124 println!("{}", verified.formatted());
125 println!(
126 "Payload: \n{}",
127 serde_json::to_string_pretty(&verified.payload()).unwrap()
128 );
129
130 Ok(())
131}18fn main() -> Result<(), Box<dyn std::error::Error>> {
19 // This key is from RFC 7515, Appendix A.2. Provide your own key instead!
20 // The key here is stored as a PKCS#8 PEM file, but you can leverage
21 // RustCrypto to load a variety of other formats.
22 let signing_key = rsa::RsaPrivateKey::from_pkcs8_pem(include_str!(concat!(
23 env!("CARGO_MANIFEST_DIR"),
24 "/examples/rfc7515a2.pem"
25 )))
26 .unwrap();
27 let verify_key: rsa::pkcs1v15::VerifyingKey<Sha256> =
28 rsa::pkcs1v15::VerifyingKey::new(signing_key.to_public_key());
29
30 // We will sign the JWT with a type-erased algorithm, and use a type-erased
31 // verifier to verify it. This allows you to use a set of verifiers which
32 // are not known at compile time.
33 let dyn_signing_key: Box<dyn TokenSigner<SignatureBytes>> = Box::new(
34 rsa::pkcs1v15::SigningKey::<Sha256>::new(signing_key.clone()),
35 );
36 let dyn_verify_key: Box<dyn TokenVerifier<SignatureBytes>> = Box::new(verify_key.clone());
37
38 // Claims can combine registered and custom fields. The claims object
39 // can be any type which implements [serde::Serialize].
40 let claims: Claims<serde_json::Value, (), String, (), ()> = Claims {
41 registered: RegisteredClaims {
42 subject: "1234567890".to_string().into(),
43 ..Default::default()
44 },
45 claims: json!({
46 "name": "John Doe",
47 "admin": true,
48 }),
49 };
50
51 // Create a token with the default headers, and no custom headers.
52 // The unit type can be used here because it implements [serde::Serialize],
53 // but a custom type could be passed if we wanted to have custom header
54 // fields.
55 let mut token = Token::compact((), claims);
56 // We can modify the headers freely before signing the JWT. In this case,
57 // we provide the `typ` header, which is optional in the JWT spec.
58 *token.header_mut().r#type() = Some("JWT".to_string());
59
60 // We can also ask that some fields be derived from the signing key, for example,
61 // this will derive the JWK field in the header from the signing key.
62 token.header_mut().key().derived();
63
64 println!("=== Initial JWT ===");
65
66 // Initially the JWT has no defined signature:
67 println!("{}", token.formatted());
68
69 // Sign the token with the algorithm, and print the result.
70 let signed = token
71 .sign::<_, SignatureBytes>(dyn_signing_key.as_ref())
72 .unwrap();
73
74 let rendered = signed.rendered().unwrap();
75
76 // We can also verify tokens.
77 let token: Token<Claims<serde_json::Value>, Unverified<()>, Compact> =
78 rendered.parse().unwrap();
79
80 println!("=== Parsed JWT ===");
81
82 // Unverified tokens can be printed for debugging, but there is deliberately
83 // no access to the payload, only to the header fields.
84 println!("JWT:");
85 println!("{}", token.formatted());
86
87 // We can use the JWK to verify that the token is signed with the correct key.
88 let hdr = token.header();
89 let jwk = hdr.key().unwrap();
90 let key: rsa::pkcs1v15::VerifyingKey<Sha256> =
91 rsa::pkcs1v15::VerifyingKey::new(rsa::RsaPublicKey::from_jwk(jwk).unwrap());
92
93 println!("=== Verification === ");
94 // Check it against the verified key
95 token
96 .clone()
97 .verify::<_, rsa::pkcs1v15::Signature>(&verify_key)
98 .unwrap();
99 println!(
100 "Verified with verify key (typed): {}",
101 type_name_of_val(&verify_key)
102 );
103
104 // Check it against the verified key
105 let verified = token
106 .clone()
107 .verify::<_, SignatureBytes>(dyn_verify_key.as_ref())
108 .unwrap();
109 println!(
110 "Verified with dyn verify key: {}",
111 type_name_of_val(&dyn_verify_key)
112 );
113
114 // Check it against its own JWT
115 token
116 .clone()
117 .verify::<_, rsa::pkcs1v15::Signature>(&key)
118 .unwrap();
119 println!("Verified with JWK");
120
121 println!("=== Verified JWT ===");
122 println!("JWT:");
123 println!("{}", verified.formatted());
124 println!(
125 "Payload: \n{}",
126 serde_json::to_string_pretty(&verified.payload()).unwrap()
127 );
128
129 Ok(())
130}Source§impl<H, Fmt, P> Token<P, Unsigned<H>, Fmt>where
Fmt: TokenFormat,
impl<H, Fmt, P> Token<P, Unsigned<H>, Fmt>where
Fmt: TokenFormat,
Sourcepub fn payload(&self) -> Option<&P>
pub fn payload(&self) -> Option<&P>
Get the payload of the token.
Examples found in repository?
75fn dyn_rsa_verify() {
76 let token = unsigned_token();
77 println!("=== Unsigned Token ===");
78 println!("{}", token.formatted());
79 println!(
80 "Payload: {}",
81 serde_json::to_string_pretty(&token.payload().unwrap()).unwrap()
82 );
83
84 let signed = token
85 .sign::<_, rsa::pkcs1v15::Signature>(&rsa_signer())
86 .unwrap();
87
88 let unverified = roundtrip(signed.unverify());
89
90 println!("=== Unverified Token ===");
91 println!("{}", unverified.formatted());
92
93 let verified = unverified
94 .verify::<_, rsa::pkcs1v15::Signature>(&rsa_verifier())
95 .unwrap();
96
97 let unverified = roundtrip(verified.unverify());
98
99 let verified = unverified
100 .verify::<_, SignatureBytes>(dyn_verifier().as_ref())
101 .unwrap();
102
103 println!("=== Verified Token ===");
104 println!("{}", verified.formatted());
105}
106
107#[test]
108fn dyn_rsa_sign() {
109 let token = unsigned_token();
110 println!("=== Unsigned Token ===");
111 println!("{}", token.formatted());
112 println!(
113 "Payload: {}",
114 serde_json::to_string_pretty(&token.payload().unwrap()).unwrap()
115 );
116
117 let signed = token
118 .sign::<_, SignatureBytes>(dyn_signer().as_ref())
119 .unwrap();
120
121 let unverified = roundtrip(signed.unverify());
122
123 println!("=== Unverified Token ===");
124 println!("{}", unverified.formatted());
125
126 let verified = unverified
127 .verify::<_, rsa::pkcs1v15::Signature>(&rsa_verifier())
128 .unwrap();
129
130 let unverified = roundtrip(verified.unverify());
131
132 let verified = unverified
133 .verify::<_, SignatureBytes>(dyn_verifier().as_ref())
134 .unwrap();
135
136 println!("=== Verified Token ===");
137 println!("{}", verified.formatted());
138}Sourcepub fn with_custom_header<H2>(self, header: H2) -> Token<P, Unsigned<H2>, Fmt>
pub fn with_custom_header<H2>(self, header: H2) -> Token<P, Unsigned<H2>, Fmt>
Replace the custom header fields of the token.
Source§impl<H, Fmt, P> Token<P, Unsigned<H>, Fmt>
impl<H, Fmt, P> Token<P, Unsigned<H>, Fmt>
Sourcepub fn sign<A, S>(
self,
algorithm: &A,
) -> Result<Token<P, Signed<H, A, S>, Fmt>, TokenSigningError>
pub fn sign<A, S>( self, algorithm: &A, ) -> Result<Token<P, Signed<H, A, S>, Fmt>, TokenSigningError>
Sign this token using the given algorithm.
This method consumes the token and returns a new one with the signature attached. Once the signature is attached, the internal fields are no longer mutable (as that would invalidate the signature), but they are still recoverable.
When using this method, you will need to specify the signature encoding type along
with the algorithm (i.e. both parameters A and S). The algorithm does not uniquely
identify the signature kind, and so it is not possible to infer the signature type
from just the algorithm type. For example, all included algorithms also implement
signing for the crate::algorithms::SignatureBytes type, which is a raw byte array,
suitable for use with any signature (and appropriate for use when you don’t want to
statically specify the signature type, see the dyn-key example).
§Example: Signing with a key
let key = rsa::pkcs1v15::SigningKey::random(&mut rand::OsRng, 2048).unwrap();
let token = Token::compact((), ());
// The only way to get a signed token is to sign an Unsigned token!
let signed = token.sign::<rsa::pkcs1v15::SigningKey<sha2::Sha256>, rsa::pkcs1v15::Signature>(&key).unwrap();
println!("Token: {}", signed.rendered().unwrap());Signing often requires specifying the algorithm to use. In the example above, we use
RS256, which is the RSA-PKCS1-v1-5 signature algorithm with SHA-256. The algorithm is
specified by constraining the type of key when calling Token::sign.
Examples found in repository?
75fn dyn_rsa_verify() {
76 let token = unsigned_token();
77 println!("=== Unsigned Token ===");
78 println!("{}", token.formatted());
79 println!(
80 "Payload: {}",
81 serde_json::to_string_pretty(&token.payload().unwrap()).unwrap()
82 );
83
84 let signed = token
85 .sign::<_, rsa::pkcs1v15::Signature>(&rsa_signer())
86 .unwrap();
87
88 let unverified = roundtrip(signed.unverify());
89
90 println!("=== Unverified Token ===");
91 println!("{}", unverified.formatted());
92
93 let verified = unverified
94 .verify::<_, rsa::pkcs1v15::Signature>(&rsa_verifier())
95 .unwrap();
96
97 let unverified = roundtrip(verified.unverify());
98
99 let verified = unverified
100 .verify::<_, SignatureBytes>(dyn_verifier().as_ref())
101 .unwrap();
102
103 println!("=== Verified Token ===");
104 println!("{}", verified.formatted());
105}
106
107#[test]
108fn dyn_rsa_sign() {
109 let token = unsigned_token();
110 println!("=== Unsigned Token ===");
111 println!("{}", token.formatted());
112 println!(
113 "Payload: {}",
114 serde_json::to_string_pretty(&token.payload().unwrap()).unwrap()
115 );
116
117 let signed = token
118 .sign::<_, SignatureBytes>(dyn_signer().as_ref())
119 .unwrap();
120
121 let unverified = roundtrip(signed.unverify());
122
123 println!("=== Unverified Token ===");
124 println!("{}", unverified.formatted());
125
126 let verified = unverified
127 .verify::<_, rsa::pkcs1v15::Signature>(&rsa_verifier())
128 .unwrap();
129
130 let unverified = roundtrip(verified.unverify());
131
132 let verified = unverified
133 .verify::<_, SignatureBytes>(dyn_verifier().as_ref())
134 .unwrap();
135
136 println!("=== Verified Token ===");
137 println!("{}", verified.formatted());
138}More examples
36fn main() {
37 // This key is from RFC 7515, Appendix A.2. Provide your own key instead!
38 // The key here is stored as a PKCS#8 PEM file, but you can leverage
39 // RustCrypto to load a variety of other formats.
40 let key = rsa::RsaPrivateKey::from_pkcs8_pem(include_str!(concat!(
41 env!("CARGO_MANIFEST_DIR"),
42 "/examples/rfc7515a2.pem"
43 )))
44 .unwrap();
45
46 // We will sign the JWT with the RS256 algorithm: RSA with SHA-256.
47 // RsaPkcs1v15 is really an alias to the digital signature algorithm
48 // implementation in the `rsa` crate, but provided in JAWS to make
49 // it clear which types are compatible with JWTs.
50 let alg = rsa::pkcs1v15::SigningKey::<Sha256>::new(key);
51
52 let payload = json!({
53 "termsOfServiceAgreed": true,
54 "contact": [
55 "mailto:cert-admin@example.org",
56 "mailto:admin@example.org"
57 ]
58 });
59
60 let header = json!({
61 "nonce": "6S8IqOGY7eL2lsGoTZYifg",
62 "url": "https://example.com/acme/new-account"
63 });
64
65 // Create a token with the default headers, and no custom headers.
66 let mut token = Token::new(payload, header, Compact);
67 // Request that the token header include a JWK field.
68 token.header_mut().key().derived();
69
70 // Sign the token with the algorithm and key we specified above.
71 let signed = token.sign::<_, rsa::pkcs1v15::Signature>(&alg).unwrap();
72
73 // Print the token in the ACME example format.
74 println!("{}", signed.formatted());
75}36fn main() -> Result<(), Box<dyn std::error::Error>> {
37 // This key is from RFC 7515, Appendix A.2. Provide your own key instead!
38 // The key here is stored as a PKCS#8 PEM file, but you can leverage
39 // RustCrypto to load a variety of other formats.
40 let key = rsa::RsaPrivateKey::from_pkcs8_pem(include_str!(concat!(
41 env!("CARGO_MANIFEST_DIR"),
42 "/examples/rfc7515a2.pem"
43 )))
44 .unwrap();
45
46 // We will sign the JWT with the RS256 algorithm: RSA with SHA-256.
47 let alg = rsa::pkcs1v15::SigningKey::<Sha256>::new(key);
48
49 // Claims can combine registered and custom fields. The claims object
50 // can be any type which implements [serde::Serialize].
51 let claims: Claims<serde_json::Value, (), String, (), ()> = Claims {
52 registered: RegisteredClaims {
53 subject: "1234567890".to_string().into(),
54 ..Default::default()
55 },
56 claims: json!({
57 "name": "John Doe",
58 "admin": true,
59 }),
60 };
61
62 // Create a token with the default headers, and no custom headers.
63 // The unit type can be used here because it implements [serde::Serialize],
64 // but a custom type could be passed if we wanted to have custom header
65 // fields.
66 let mut token = Token::compact((), claims);
67
68 // We can modify the headers freely before signing the JWT. In this case,
69 // we provide the `typ` header, which is optional in the JWT spec.
70 *token.header_mut().r#type() = Some("JWT".to_string());
71
72 // We can also ask that some fields be derived from the signing key, for example,
73 // this will derive the JWK field in the header from the signing key.
74 token.header_mut().key().derived();
75
76 println!("=== Initial JWT ===");
77 // Initially the JWT has no defined signature:
78 println!("{}", token.formatted());
79
80 // Sign the token with the algorithm, and print the result.
81 let signed = token.sign::<_, rsa::pkcs1v15::Signature>(&alg).unwrap();
82
83 println!("=== Signed JWT ===");
84
85 println!("JWT:");
86 println!("{}", signed.formatted());
87 println!("Token: {}", signed.rendered().unwrap());
88
89 // We can't modify the token after signing it (that would change the signature)
90 // but we can access fields and read from them:
91 println!(
92 "Type: {:?}, Algorithm: {:?}",
93 signed.header().r#type(),
94 signed.header().algorithm(),
95 );
96
97 // We can also verify tokens.
98 let token: Token<Claims<serde_json::Value>, Unverified<()>, Compact> =
99 signed.rendered().unwrap().parse().unwrap();
100
101 println!("=== Parsed JWT ===");
102
103 // Unverified tokens can be printed for debugging, but there is deliberately
104 // no access to the payload, only to the header fields.
105 println!("JWT:");
106 println!("{}", token.formatted());
107
108 // We can use the JWK to verify that the token is signed with the correct key.
109 let hdr = token.header();
110 let jwk = hdr.key().unwrap();
111 let key = rsa::RsaPublicKey::from_jwk(jwk).unwrap();
112
113 assert_eq!(&key, alg.verifying_key().as_ref());
114 println!("=== Verification === ");
115 let alg: rsa::pkcs1v15::VerifyingKey<Sha256> = alg.verifying_key();
116
117 // We can't access the claims until we verify the token.
118 let verified = token
119 .verify::<_, jaws::algorithms::SignatureBytes>(&alg)
120 .unwrap();
121
122 println!("=== Verified JWT ===");
123 println!("JWT:");
124 println!("{}", verified.formatted());
125 println!(
126 "Payload: \n{}",
127 serde_json::to_string_pretty(&verified.payload()).unwrap()
128 );
129
130 Ok(())
131}18fn main() -> Result<(), Box<dyn std::error::Error>> {
19 // This key is from RFC 7515, Appendix A.2. Provide your own key instead!
20 // The key here is stored as a PKCS#8 PEM file, but you can leverage
21 // RustCrypto to load a variety of other formats.
22 let signing_key = rsa::RsaPrivateKey::from_pkcs8_pem(include_str!(concat!(
23 env!("CARGO_MANIFEST_DIR"),
24 "/examples/rfc7515a2.pem"
25 )))
26 .unwrap();
27 let verify_key: rsa::pkcs1v15::VerifyingKey<Sha256> =
28 rsa::pkcs1v15::VerifyingKey::new(signing_key.to_public_key());
29
30 // We will sign the JWT with a type-erased algorithm, and use a type-erased
31 // verifier to verify it. This allows you to use a set of verifiers which
32 // are not known at compile time.
33 let dyn_signing_key: Box<dyn TokenSigner<SignatureBytes>> = Box::new(
34 rsa::pkcs1v15::SigningKey::<Sha256>::new(signing_key.clone()),
35 );
36 let dyn_verify_key: Box<dyn TokenVerifier<SignatureBytes>> = Box::new(verify_key.clone());
37
38 // Claims can combine registered and custom fields. The claims object
39 // can be any type which implements [serde::Serialize].
40 let claims: Claims<serde_json::Value, (), String, (), ()> = Claims {
41 registered: RegisteredClaims {
42 subject: "1234567890".to_string().into(),
43 ..Default::default()
44 },
45 claims: json!({
46 "name": "John Doe",
47 "admin": true,
48 }),
49 };
50
51 // Create a token with the default headers, and no custom headers.
52 // The unit type can be used here because it implements [serde::Serialize],
53 // but a custom type could be passed if we wanted to have custom header
54 // fields.
55 let mut token = Token::compact((), claims);
56 // We can modify the headers freely before signing the JWT. In this case,
57 // we provide the `typ` header, which is optional in the JWT spec.
58 *token.header_mut().r#type() = Some("JWT".to_string());
59
60 // We can also ask that some fields be derived from the signing key, for example,
61 // this will derive the JWK field in the header from the signing key.
62 token.header_mut().key().derived();
63
64 println!("=== Initial JWT ===");
65
66 // Initially the JWT has no defined signature:
67 println!("{}", token.formatted());
68
69 // Sign the token with the algorithm, and print the result.
70 let signed = token
71 .sign::<_, SignatureBytes>(dyn_signing_key.as_ref())
72 .unwrap();
73
74 let rendered = signed.rendered().unwrap();
75
76 // We can also verify tokens.
77 let token: Token<Claims<serde_json::Value>, Unverified<()>, Compact> =
78 rendered.parse().unwrap();
79
80 println!("=== Parsed JWT ===");
81
82 // Unverified tokens can be printed for debugging, but there is deliberately
83 // no access to the payload, only to the header fields.
84 println!("JWT:");
85 println!("{}", token.formatted());
86
87 // We can use the JWK to verify that the token is signed with the correct key.
88 let hdr = token.header();
89 let jwk = hdr.key().unwrap();
90 let key: rsa::pkcs1v15::VerifyingKey<Sha256> =
91 rsa::pkcs1v15::VerifyingKey::new(rsa::RsaPublicKey::from_jwk(jwk).unwrap());
92
93 println!("=== Verification === ");
94 // Check it against the verified key
95 token
96 .clone()
97 .verify::<_, rsa::pkcs1v15::Signature>(&verify_key)
98 .unwrap();
99 println!(
100 "Verified with verify key (typed): {}",
101 type_name_of_val(&verify_key)
102 );
103
104 // Check it against the verified key
105 let verified = token
106 .clone()
107 .verify::<_, SignatureBytes>(dyn_verify_key.as_ref())
108 .unwrap();
109 println!(
110 "Verified with dyn verify key: {}",
111 type_name_of_val(&dyn_verify_key)
112 );
113
114 // Check it against its own JWT
115 token
116 .clone()
117 .verify::<_, rsa::pkcs1v15::Signature>(&key)
118 .unwrap();
119 println!("Verified with JWK");
120
121 println!("=== Verified JWT ===");
122 println!("JWT:");
123 println!("{}", verified.formatted());
124 println!(
125 "Payload: \n{}",
126 serde_json::to_string_pretty(&verified.payload()).unwrap()
127 );
128
129 Ok(())
130}Sourcepub fn sign_randomized<A, S>(
self,
algorithm: &A,
rng: &mut impl CryptoRngCore,
) -> Result<Token<P, Signed<H, A, S>, Fmt>, TokenSigningError>
Available on crate feature rand only.
pub fn sign_randomized<A, S>( self, algorithm: &A, rng: &mut impl CryptoRngCore, ) -> Result<Token<P, Signed<H, A, S>, Fmt>, TokenSigningError>
rand only.Sign this token using the given algorithm, and a random number generator.
Source§impl<H, Fmt, P> Token<P, Unverified<H>, Fmt>
impl<H, Fmt, P> Token<P, Unverified<H>, Fmt>
Sourcepub fn verify<A, S>(
self,
algorithm: &A,
) -> Result<Token<P, Verified<H, A, S>, Fmt>, TokenVerifyingError>
pub fn verify<A, S>( self, algorithm: &A, ) -> Result<Token<P, Verified<H, A, S>, Fmt>, TokenVerifyingError>
Verify the signature of the token with the given algorithm.
This method consumes the token and returns a new one with the signature verified.
The algorithm must be uniquely specified for verification, otherwise the token could perform a signature downgrade attack.
Examples found in repository?
75fn dyn_rsa_verify() {
76 let token = unsigned_token();
77 println!("=== Unsigned Token ===");
78 println!("{}", token.formatted());
79 println!(
80 "Payload: {}",
81 serde_json::to_string_pretty(&token.payload().unwrap()).unwrap()
82 );
83
84 let signed = token
85 .sign::<_, rsa::pkcs1v15::Signature>(&rsa_signer())
86 .unwrap();
87
88 let unverified = roundtrip(signed.unverify());
89
90 println!("=== Unverified Token ===");
91 println!("{}", unverified.formatted());
92
93 let verified = unverified
94 .verify::<_, rsa::pkcs1v15::Signature>(&rsa_verifier())
95 .unwrap();
96
97 let unverified = roundtrip(verified.unverify());
98
99 let verified = unverified
100 .verify::<_, SignatureBytes>(dyn_verifier().as_ref())
101 .unwrap();
102
103 println!("=== Verified Token ===");
104 println!("{}", verified.formatted());
105}
106
107#[test]
108fn dyn_rsa_sign() {
109 let token = unsigned_token();
110 println!("=== Unsigned Token ===");
111 println!("{}", token.formatted());
112 println!(
113 "Payload: {}",
114 serde_json::to_string_pretty(&token.payload().unwrap()).unwrap()
115 );
116
117 let signed = token
118 .sign::<_, SignatureBytes>(dyn_signer().as_ref())
119 .unwrap();
120
121 let unverified = roundtrip(signed.unverify());
122
123 println!("=== Unverified Token ===");
124 println!("{}", unverified.formatted());
125
126 let verified = unverified
127 .verify::<_, rsa::pkcs1v15::Signature>(&rsa_verifier())
128 .unwrap();
129
130 let unverified = roundtrip(verified.unverify());
131
132 let verified = unverified
133 .verify::<_, SignatureBytes>(dyn_verifier().as_ref())
134 .unwrap();
135
136 println!("=== Verified Token ===");
137 println!("{}", verified.formatted());
138}More examples
36fn main() -> Result<(), Box<dyn std::error::Error>> {
37 // This key is from RFC 7515, Appendix A.2. Provide your own key instead!
38 // The key here is stored as a PKCS#8 PEM file, but you can leverage
39 // RustCrypto to load a variety of other formats.
40 let key = rsa::RsaPrivateKey::from_pkcs8_pem(include_str!(concat!(
41 env!("CARGO_MANIFEST_DIR"),
42 "/examples/rfc7515a2.pem"
43 )))
44 .unwrap();
45
46 // We will sign the JWT with the RS256 algorithm: RSA with SHA-256.
47 let alg = rsa::pkcs1v15::SigningKey::<Sha256>::new(key);
48
49 // Claims can combine registered and custom fields. The claims object
50 // can be any type which implements [serde::Serialize].
51 let claims: Claims<serde_json::Value, (), String, (), ()> = Claims {
52 registered: RegisteredClaims {
53 subject: "1234567890".to_string().into(),
54 ..Default::default()
55 },
56 claims: json!({
57 "name": "John Doe",
58 "admin": true,
59 }),
60 };
61
62 // Create a token with the default headers, and no custom headers.
63 // The unit type can be used here because it implements [serde::Serialize],
64 // but a custom type could be passed if we wanted to have custom header
65 // fields.
66 let mut token = Token::compact((), claims);
67
68 // We can modify the headers freely before signing the JWT. In this case,
69 // we provide the `typ` header, which is optional in the JWT spec.
70 *token.header_mut().r#type() = Some("JWT".to_string());
71
72 // We can also ask that some fields be derived from the signing key, for example,
73 // this will derive the JWK field in the header from the signing key.
74 token.header_mut().key().derived();
75
76 println!("=== Initial JWT ===");
77 // Initially the JWT has no defined signature:
78 println!("{}", token.formatted());
79
80 // Sign the token with the algorithm, and print the result.
81 let signed = token.sign::<_, rsa::pkcs1v15::Signature>(&alg).unwrap();
82
83 println!("=== Signed JWT ===");
84
85 println!("JWT:");
86 println!("{}", signed.formatted());
87 println!("Token: {}", signed.rendered().unwrap());
88
89 // We can't modify the token after signing it (that would change the signature)
90 // but we can access fields and read from them:
91 println!(
92 "Type: {:?}, Algorithm: {:?}",
93 signed.header().r#type(),
94 signed.header().algorithm(),
95 );
96
97 // We can also verify tokens.
98 let token: Token<Claims<serde_json::Value>, Unverified<()>, Compact> =
99 signed.rendered().unwrap().parse().unwrap();
100
101 println!("=== Parsed JWT ===");
102
103 // Unverified tokens can be printed for debugging, but there is deliberately
104 // no access to the payload, only to the header fields.
105 println!("JWT:");
106 println!("{}", token.formatted());
107
108 // We can use the JWK to verify that the token is signed with the correct key.
109 let hdr = token.header();
110 let jwk = hdr.key().unwrap();
111 let key = rsa::RsaPublicKey::from_jwk(jwk).unwrap();
112
113 assert_eq!(&key, alg.verifying_key().as_ref());
114 println!("=== Verification === ");
115 let alg: rsa::pkcs1v15::VerifyingKey<Sha256> = alg.verifying_key();
116
117 // We can't access the claims until we verify the token.
118 let verified = token
119 .verify::<_, jaws::algorithms::SignatureBytes>(&alg)
120 .unwrap();
121
122 println!("=== Verified JWT ===");
123 println!("JWT:");
124 println!("{}", verified.formatted());
125 println!(
126 "Payload: \n{}",
127 serde_json::to_string_pretty(&verified.payload()).unwrap()
128 );
129
130 Ok(())
131}18fn main() -> Result<(), Box<dyn std::error::Error>> {
19 // This key is from RFC 7515, Appendix A.2. Provide your own key instead!
20 // The key here is stored as a PKCS#8 PEM file, but you can leverage
21 // RustCrypto to load a variety of other formats.
22 let signing_key = rsa::RsaPrivateKey::from_pkcs8_pem(include_str!(concat!(
23 env!("CARGO_MANIFEST_DIR"),
24 "/examples/rfc7515a2.pem"
25 )))
26 .unwrap();
27 let verify_key: rsa::pkcs1v15::VerifyingKey<Sha256> =
28 rsa::pkcs1v15::VerifyingKey::new(signing_key.to_public_key());
29
30 // We will sign the JWT with a type-erased algorithm, and use a type-erased
31 // verifier to verify it. This allows you to use a set of verifiers which
32 // are not known at compile time.
33 let dyn_signing_key: Box<dyn TokenSigner<SignatureBytes>> = Box::new(
34 rsa::pkcs1v15::SigningKey::<Sha256>::new(signing_key.clone()),
35 );
36 let dyn_verify_key: Box<dyn TokenVerifier<SignatureBytes>> = Box::new(verify_key.clone());
37
38 // Claims can combine registered and custom fields. The claims object
39 // can be any type which implements [serde::Serialize].
40 let claims: Claims<serde_json::Value, (), String, (), ()> = Claims {
41 registered: RegisteredClaims {
42 subject: "1234567890".to_string().into(),
43 ..Default::default()
44 },
45 claims: json!({
46 "name": "John Doe",
47 "admin": true,
48 }),
49 };
50
51 // Create a token with the default headers, and no custom headers.
52 // The unit type can be used here because it implements [serde::Serialize],
53 // but a custom type could be passed if we wanted to have custom header
54 // fields.
55 let mut token = Token::compact((), claims);
56 // We can modify the headers freely before signing the JWT. In this case,
57 // we provide the `typ` header, which is optional in the JWT spec.
58 *token.header_mut().r#type() = Some("JWT".to_string());
59
60 // We can also ask that some fields be derived from the signing key, for example,
61 // this will derive the JWK field in the header from the signing key.
62 token.header_mut().key().derived();
63
64 println!("=== Initial JWT ===");
65
66 // Initially the JWT has no defined signature:
67 println!("{}", token.formatted());
68
69 // Sign the token with the algorithm, and print the result.
70 let signed = token
71 .sign::<_, SignatureBytes>(dyn_signing_key.as_ref())
72 .unwrap();
73
74 let rendered = signed.rendered().unwrap();
75
76 // We can also verify tokens.
77 let token: Token<Claims<serde_json::Value>, Unverified<()>, Compact> =
78 rendered.parse().unwrap();
79
80 println!("=== Parsed JWT ===");
81
82 // Unverified tokens can be printed for debugging, but there is deliberately
83 // no access to the payload, only to the header fields.
84 println!("JWT:");
85 println!("{}", token.formatted());
86
87 // We can use the JWK to verify that the token is signed with the correct key.
88 let hdr = token.header();
89 let jwk = hdr.key().unwrap();
90 let key: rsa::pkcs1v15::VerifyingKey<Sha256> =
91 rsa::pkcs1v15::VerifyingKey::new(rsa::RsaPublicKey::from_jwk(jwk).unwrap());
92
93 println!("=== Verification === ");
94 // Check it against the verified key
95 token
96 .clone()
97 .verify::<_, rsa::pkcs1v15::Signature>(&verify_key)
98 .unwrap();
99 println!(
100 "Verified with verify key (typed): {}",
101 type_name_of_val(&verify_key)
102 );
103
104 // Check it against the verified key
105 let verified = token
106 .clone()
107 .verify::<_, SignatureBytes>(dyn_verify_key.as_ref())
108 .unwrap();
109 println!(
110 "Verified with dyn verify key: {}",
111 type_name_of_val(&dyn_verify_key)
112 );
113
114 // Check it against its own JWT
115 token
116 .clone()
117 .verify::<_, rsa::pkcs1v15::Signature>(&key)
118 .unwrap();
119 println!("Verified with JWK");
120
121 println!("=== Verified JWT ===");
122 println!("JWT:");
123 println!("{}", verified.formatted());
124 println!(
125 "Payload: \n{}",
126 serde_json::to_string_pretty(&verified.payload()).unwrap()
127 );
128
129 Ok(())
130}Source§impl<P, H, Alg, Sig, Fmt> Token<P, Signed<H, Alg, Sig>, Fmt>where
Fmt: TokenFormat,
Alg: DynJsonWebAlgorithm + ?Sized,
Sig: SignatureEncoding,
H: Serialize,
P: Serialize,
impl<P, H, Alg, Sig, Fmt> Token<P, Signed<H, Alg, Sig>, Fmt>where
Fmt: TokenFormat,
Alg: DynJsonWebAlgorithm + ?Sized,
Sig: SignatureEncoding,
H: Serialize,
P: Serialize,
Sourcepub fn unverify(self) -> Token<P, Unverified<H>, Fmt>
pub fn unverify(self) -> Token<P, Unverified<H>, Fmt>
Transition the token back into an unverified state.
This method consumes the token and returns a new one, which still includes the signature but which is no longer considered verified.
Examples found in repository?
75fn dyn_rsa_verify() {
76 let token = unsigned_token();
77 println!("=== Unsigned Token ===");
78 println!("{}", token.formatted());
79 println!(
80 "Payload: {}",
81 serde_json::to_string_pretty(&token.payload().unwrap()).unwrap()
82 );
83
84 let signed = token
85 .sign::<_, rsa::pkcs1v15::Signature>(&rsa_signer())
86 .unwrap();
87
88 let unverified = roundtrip(signed.unverify());
89
90 println!("=== Unverified Token ===");
91 println!("{}", unverified.formatted());
92
93 let verified = unverified
94 .verify::<_, rsa::pkcs1v15::Signature>(&rsa_verifier())
95 .unwrap();
96
97 let unverified = roundtrip(verified.unverify());
98
99 let verified = unverified
100 .verify::<_, SignatureBytes>(dyn_verifier().as_ref())
101 .unwrap();
102
103 println!("=== Verified Token ===");
104 println!("{}", verified.formatted());
105}
106
107#[test]
108fn dyn_rsa_sign() {
109 let token = unsigned_token();
110 println!("=== Unsigned Token ===");
111 println!("{}", token.formatted());
112 println!(
113 "Payload: {}",
114 serde_json::to_string_pretty(&token.payload().unwrap()).unwrap()
115 );
116
117 let signed = token
118 .sign::<_, SignatureBytes>(dyn_signer().as_ref())
119 .unwrap();
120
121 let unverified = roundtrip(signed.unverify());
122
123 println!("=== Unverified Token ===");
124 println!("{}", unverified.formatted());
125
126 let verified = unverified
127 .verify::<_, rsa::pkcs1v15::Signature>(&rsa_verifier())
128 .unwrap();
129
130 let unverified = roundtrip(verified.unverify());
131
132 let verified = unverified
133 .verify::<_, SignatureBytes>(dyn_verifier().as_ref())
134 .unwrap();
135
136 println!("=== Verified Token ===");
137 println!("{}", verified.formatted());
138}Source§impl<P, H, Alg, Sig, Fmt> Token<P, Verified<H, Alg, Sig>, Fmt>where
Fmt: TokenFormat,
Alg: DynJsonWebAlgorithm + ?Sized,
Sig: SignatureEncoding,
H: Serialize,
P: Serialize,
impl<P, H, Alg, Sig, Fmt> Token<P, Verified<H, Alg, Sig>, Fmt>where
Fmt: TokenFormat,
Alg: DynJsonWebAlgorithm + ?Sized,
Sig: SignatureEncoding,
H: Serialize,
P: Serialize,
Sourcepub fn unverify(self) -> Token<P, Unverified<H>, Fmt>
pub fn unverify(self) -> Token<P, Unverified<H>, Fmt>
Transition the token back into an unverified state.
This method consumes the token and returns a new one, which still includes the signature but which is no longer considered verified.
Examples found in repository?
75fn dyn_rsa_verify() {
76 let token = unsigned_token();
77 println!("=== Unsigned Token ===");
78 println!("{}", token.formatted());
79 println!(
80 "Payload: {}",
81 serde_json::to_string_pretty(&token.payload().unwrap()).unwrap()
82 );
83
84 let signed = token
85 .sign::<_, rsa::pkcs1v15::Signature>(&rsa_signer())
86 .unwrap();
87
88 let unverified = roundtrip(signed.unverify());
89
90 println!("=== Unverified Token ===");
91 println!("{}", unverified.formatted());
92
93 let verified = unverified
94 .verify::<_, rsa::pkcs1v15::Signature>(&rsa_verifier())
95 .unwrap();
96
97 let unverified = roundtrip(verified.unverify());
98
99 let verified = unverified
100 .verify::<_, SignatureBytes>(dyn_verifier().as_ref())
101 .unwrap();
102
103 println!("=== Verified Token ===");
104 println!("{}", verified.formatted());
105}
106
107#[test]
108fn dyn_rsa_sign() {
109 let token = unsigned_token();
110 println!("=== Unsigned Token ===");
111 println!("{}", token.formatted());
112 println!(
113 "Payload: {}",
114 serde_json::to_string_pretty(&token.payload().unwrap()).unwrap()
115 );
116
117 let signed = token
118 .sign::<_, SignatureBytes>(dyn_signer().as_ref())
119 .unwrap();
120
121 let unverified = roundtrip(signed.unverify());
122
123 println!("=== Unverified Token ===");
124 println!("{}", unverified.formatted());
125
126 let verified = unverified
127 .verify::<_, rsa::pkcs1v15::Signature>(&rsa_verifier())
128 .unwrap();
129
130 let unverified = roundtrip(verified.unverify());
131
132 let verified = unverified
133 .verify::<_, SignatureBytes>(dyn_verifier().as_ref())
134 .unwrap();
135
136 println!("=== Verified Token ===");
137 println!("{}", verified.formatted());
138}Source§impl<H, Fmt, P, Alg, Sig> Token<P, Verified<H, Alg, Sig>, Fmt>
impl<H, Fmt, P, Alg, Sig> Token<P, Verified<H, Alg, Sig>, Fmt>
Sourcepub fn payload(&self) -> Option<&P>
pub fn payload(&self) -> Option<&P>
Get the payload of the token.
Examples found in repository?
36fn main() -> Result<(), Box<dyn std::error::Error>> {
37 // This key is from RFC 7515, Appendix A.2. Provide your own key instead!
38 // The key here is stored as a PKCS#8 PEM file, but you can leverage
39 // RustCrypto to load a variety of other formats.
40 let key = rsa::RsaPrivateKey::from_pkcs8_pem(include_str!(concat!(
41 env!("CARGO_MANIFEST_DIR"),
42 "/examples/rfc7515a2.pem"
43 )))
44 .unwrap();
45
46 // We will sign the JWT with the RS256 algorithm: RSA with SHA-256.
47 let alg = rsa::pkcs1v15::SigningKey::<Sha256>::new(key);
48
49 // Claims can combine registered and custom fields. The claims object
50 // can be any type which implements [serde::Serialize].
51 let claims: Claims<serde_json::Value, (), String, (), ()> = Claims {
52 registered: RegisteredClaims {
53 subject: "1234567890".to_string().into(),
54 ..Default::default()
55 },
56 claims: json!({
57 "name": "John Doe",
58 "admin": true,
59 }),
60 };
61
62 // Create a token with the default headers, and no custom headers.
63 // The unit type can be used here because it implements [serde::Serialize],
64 // but a custom type could be passed if we wanted to have custom header
65 // fields.
66 let mut token = Token::compact((), claims);
67
68 // We can modify the headers freely before signing the JWT. In this case,
69 // we provide the `typ` header, which is optional in the JWT spec.
70 *token.header_mut().r#type() = Some("JWT".to_string());
71
72 // We can also ask that some fields be derived from the signing key, for example,
73 // this will derive the JWK field in the header from the signing key.
74 token.header_mut().key().derived();
75
76 println!("=== Initial JWT ===");
77 // Initially the JWT has no defined signature:
78 println!("{}", token.formatted());
79
80 // Sign the token with the algorithm, and print the result.
81 let signed = token.sign::<_, rsa::pkcs1v15::Signature>(&alg).unwrap();
82
83 println!("=== Signed JWT ===");
84
85 println!("JWT:");
86 println!("{}", signed.formatted());
87 println!("Token: {}", signed.rendered().unwrap());
88
89 // We can't modify the token after signing it (that would change the signature)
90 // but we can access fields and read from them:
91 println!(
92 "Type: {:?}, Algorithm: {:?}",
93 signed.header().r#type(),
94 signed.header().algorithm(),
95 );
96
97 // We can also verify tokens.
98 let token: Token<Claims<serde_json::Value>, Unverified<()>, Compact> =
99 signed.rendered().unwrap().parse().unwrap();
100
101 println!("=== Parsed JWT ===");
102
103 // Unverified tokens can be printed for debugging, but there is deliberately
104 // no access to the payload, only to the header fields.
105 println!("JWT:");
106 println!("{}", token.formatted());
107
108 // We can use the JWK to verify that the token is signed with the correct key.
109 let hdr = token.header();
110 let jwk = hdr.key().unwrap();
111 let key = rsa::RsaPublicKey::from_jwk(jwk).unwrap();
112
113 assert_eq!(&key, alg.verifying_key().as_ref());
114 println!("=== Verification === ");
115 let alg: rsa::pkcs1v15::VerifyingKey<Sha256> = alg.verifying_key();
116
117 // We can't access the claims until we verify the token.
118 let verified = token
119 .verify::<_, jaws::algorithms::SignatureBytes>(&alg)
120 .unwrap();
121
122 println!("=== Verified JWT ===");
123 println!("JWT:");
124 println!("{}", verified.formatted());
125 println!(
126 "Payload: \n{}",
127 serde_json::to_string_pretty(&verified.payload()).unwrap()
128 );
129
130 Ok(())
131}More examples
18fn main() -> Result<(), Box<dyn std::error::Error>> {
19 // This key is from RFC 7515, Appendix A.2. Provide your own key instead!
20 // The key here is stored as a PKCS#8 PEM file, but you can leverage
21 // RustCrypto to load a variety of other formats.
22 let signing_key = rsa::RsaPrivateKey::from_pkcs8_pem(include_str!(concat!(
23 env!("CARGO_MANIFEST_DIR"),
24 "/examples/rfc7515a2.pem"
25 )))
26 .unwrap();
27 let verify_key: rsa::pkcs1v15::VerifyingKey<Sha256> =
28 rsa::pkcs1v15::VerifyingKey::new(signing_key.to_public_key());
29
30 // We will sign the JWT with a type-erased algorithm, and use a type-erased
31 // verifier to verify it. This allows you to use a set of verifiers which
32 // are not known at compile time.
33 let dyn_signing_key: Box<dyn TokenSigner<SignatureBytes>> = Box::new(
34 rsa::pkcs1v15::SigningKey::<Sha256>::new(signing_key.clone()),
35 );
36 let dyn_verify_key: Box<dyn TokenVerifier<SignatureBytes>> = Box::new(verify_key.clone());
37
38 // Claims can combine registered and custom fields. The claims object
39 // can be any type which implements [serde::Serialize].
40 let claims: Claims<serde_json::Value, (), String, (), ()> = Claims {
41 registered: RegisteredClaims {
42 subject: "1234567890".to_string().into(),
43 ..Default::default()
44 },
45 claims: json!({
46 "name": "John Doe",
47 "admin": true,
48 }),
49 };
50
51 // Create a token with the default headers, and no custom headers.
52 // The unit type can be used here because it implements [serde::Serialize],
53 // but a custom type could be passed if we wanted to have custom header
54 // fields.
55 let mut token = Token::compact((), claims);
56 // We can modify the headers freely before signing the JWT. In this case,
57 // we provide the `typ` header, which is optional in the JWT spec.
58 *token.header_mut().r#type() = Some("JWT".to_string());
59
60 // We can also ask that some fields be derived from the signing key, for example,
61 // this will derive the JWK field in the header from the signing key.
62 token.header_mut().key().derived();
63
64 println!("=== Initial JWT ===");
65
66 // Initially the JWT has no defined signature:
67 println!("{}", token.formatted());
68
69 // Sign the token with the algorithm, and print the result.
70 let signed = token
71 .sign::<_, SignatureBytes>(dyn_signing_key.as_ref())
72 .unwrap();
73
74 let rendered = signed.rendered().unwrap();
75
76 // We can also verify tokens.
77 let token: Token<Claims<serde_json::Value>, Unverified<()>, Compact> =
78 rendered.parse().unwrap();
79
80 println!("=== Parsed JWT ===");
81
82 // Unverified tokens can be printed for debugging, but there is deliberately
83 // no access to the payload, only to the header fields.
84 println!("JWT:");
85 println!("{}", token.formatted());
86
87 // We can use the JWK to verify that the token is signed with the correct key.
88 let hdr = token.header();
89 let jwk = hdr.key().unwrap();
90 let key: rsa::pkcs1v15::VerifyingKey<Sha256> =
91 rsa::pkcs1v15::VerifyingKey::new(rsa::RsaPublicKey::from_jwk(jwk).unwrap());
92
93 println!("=== Verification === ");
94 // Check it against the verified key
95 token
96 .clone()
97 .verify::<_, rsa::pkcs1v15::Signature>(&verify_key)
98 .unwrap();
99 println!(
100 "Verified with verify key (typed): {}",
101 type_name_of_val(&verify_key)
102 );
103
104 // Check it against the verified key
105 let verified = token
106 .clone()
107 .verify::<_, SignatureBytes>(dyn_verify_key.as_ref())
108 .unwrap();
109 println!(
110 "Verified with dyn verify key: {}",
111 type_name_of_val(&dyn_verify_key)
112 );
113
114 // Check it against its own JWT
115 token
116 .clone()
117 .verify::<_, rsa::pkcs1v15::Signature>(&key)
118 .unwrap();
119 println!("Verified with JWK");
120
121 println!("=== Verified JWT ===");
122 println!("JWT:");
123 println!("{}", verified.formatted());
124 println!(
125 "Payload: \n{}",
126 serde_json::to_string_pretty(&verified.payload()).unwrap()
127 );
128
129 Ok(())
130}Trait Implementations§
Source§impl<P: Clone, State: Clone + MaybeSigned, Fmt: Clone + TokenFormat> Clone for Token<P, State, Fmt>
impl<P: Clone, State: Clone + MaybeSigned, Fmt: Clone + TokenFormat> Clone for Token<P, State, Fmt>
Source§impl<P: Debug, State: Debug + MaybeSigned, Fmt: Debug + TokenFormat> Debug for Token<P, State, Fmt>
impl<P: Debug, State: Debug + MaybeSigned, Fmt: Debug + TokenFormat> Debug for Token<P, State, Fmt>
Source§impl<P, H, Fmt> FromStr for Token<P, Unverified<H>, Fmt>
impl<P, H, Fmt> FromStr for Token<P, Unverified<H>, Fmt>
Source§impl<P, S, Fmt> JWTFormat for Token<P, S, Fmt>where
S: HasSignature,
<S as MaybeSigned>::Header: Serialize,
<S as MaybeSigned>::HeaderState: HeaderState,
P: Serialize,
Fmt: TokenFormat,
Available on crate feature fmt only.
impl<P, S, Fmt> JWTFormat for Token<P, S, Fmt>where
S: HasSignature,
<S as MaybeSigned>::Header: Serialize,
<S as MaybeSigned>::HeaderState: HeaderState,
P: Serialize,
Fmt: TokenFormat,
fmt only.Source§fn fmt<W: Write>(&self, f: &mut IndentWriter<'_, W>) -> Result
fn fmt<W: Write>(&self, f: &mut IndentWriter<'_, W>) -> Result
Source§fn fmt_indented<W: Write>(&self, f: &mut IndentWriter<'_, W>) -> Result
fn fmt_indented<W: Write>(&self, f: &mut IndentWriter<'_, W>) -> Result
Source§fn fmt_indented_skip_first<W: Write>(
&self,
f: &mut IndentWriter<'_, W>,
) -> Result
fn fmt_indented_skip_first<W: Write>( &self, f: &mut IndentWriter<'_, W>, ) -> Result
Source§fn formatted(&self) -> JWTFormatted<'_, Self>
fn formatted(&self) -> JWTFormatted<'_, Self>
std::fmt::Display.Source§impl<P, H, Fmt> JWTFormat for Token<P, Unsigned<H>, Fmt>
Available on crate feature fmt only.
impl<P, H, Fmt> JWTFormat for Token<P, Unsigned<H>, Fmt>
fmt only.Source§fn fmt<W: Write>(&self, f: &mut IndentWriter<'_, W>) -> Result
fn fmt<W: Write>(&self, f: &mut IndentWriter<'_, W>) -> Result
Source§fn fmt_indented<W: Write>(&self, f: &mut IndentWriter<'_, W>) -> Result
fn fmt_indented<W: Write>(&self, f: &mut IndentWriter<'_, W>) -> Result
Source§fn fmt_indented_skip_first<W: Write>(
&self,
f: &mut IndentWriter<'_, W>,
) -> Result
fn fmt_indented_skip_first<W: Write>( &self, f: &mut IndentWriter<'_, W>, ) -> Result
Source§fn formatted(&self) -> JWTFormatted<'_, Self>
fn formatted(&self) -> JWTFormatted<'_, Self>
std::fmt::Display.