jsonwebtoken/
jws.rs

1//! JSON Web Signatures data type.
2use std::marker::PhantomData;
3
4use crate::crypto::sign;
5use crate::errors::{ErrorKind, Result, new_error};
6use crate::serialization::{DecodedJwtPartClaims, b64_encode_part};
7use crate::validation::validate;
8use crate::{DecodingKey, EncodingKey, Header, TokenData, Validation};
9
10use crate::decoding::{jwt_verifier_factory, verify_signature_body};
11use serde::de::DeserializeOwned;
12use serde::{Deserialize, Serialize};
13
14/// This is a serde-compatible JSON Web Signature structure.
15#[derive(Debug, Clone, Serialize, Deserialize)]
16pub struct Jws<C> {
17    /// The base64 encoded header data.
18    ///
19    /// Defined in [RFC7515#3.2](https://tools.ietf.org/html/rfc7515#section-3.2).
20    pub protected: String,
21    /// The base64 encoded claims data.
22    ///
23    /// Defined in [RFC7515#3.2](https://tools.ietf.org/html/rfc7515#section-3.2).
24    pub payload: String,
25    /// The signature on the other fields.
26    ///
27    /// Defined in [RFC7515#3.2](https://tools.ietf.org/html/rfc7515#section-3.2).
28    pub signature: String,
29    /// Unused, for associating type metadata.
30    #[serde(skip)]
31    pub _pd: PhantomData<C>,
32}
33
34/// Encode the header and claims given and sign the payload using the algorithm from the header and the key.
35/// If the algorithm given is RSA or EC, the key needs to be in the PEM format. This produces a JWS instead of
36/// a JWT -- usage is similar to `encode`, see that for more details.
37pub fn encode<T: Serialize>(
38    header: &Header,
39    claims: Option<&T>,
40    key: &EncodingKey,
41) -> Result<Jws<T>> {
42    if key.family != header.alg.family() {
43        return Err(new_error(ErrorKind::InvalidAlgorithm));
44    }
45    let encoded_header = b64_encode_part(header)?;
46    let encoded_claims = match claims {
47        Some(claims) => b64_encode_part(claims)?,
48        None => "".to_string(),
49    };
50    let message = [encoded_header.as_str(), encoded_claims.as_str()].join(".");
51    let signature = sign(message.as_bytes(), key, header.alg)?;
52
53    Ok(Jws {
54        protected: encoded_header,
55        payload: encoded_claims,
56        signature,
57        _pd: Default::default(),
58    })
59}
60
61/// Validate a received JWS and decode into the header and claims.
62pub fn decode<T: DeserializeOwned>(
63    jws: &Jws<T>,
64    key: &DecodingKey,
65    validation: &Validation,
66) -> Result<TokenData<T>> {
67    let header = Header::from_encoded(&jws.protected)?;
68    let message = [jws.protected.as_str(), jws.payload.as_str()].join(".");
69
70    let verifying_provider = jwt_verifier_factory(&header.alg, key)?;
71    verify_signature_body(
72        message.as_bytes(),
73        jws.signature.as_bytes(),
74        &header,
75        validation,
76        verifying_provider,
77    )?;
78
79    let decoded_claims = DecodedJwtPartClaims::from_jwt_part_claims(&jws.payload)?;
80    let claims = decoded_claims.deserialize()?;
81    validate(decoded_claims.deserialize()?, validation)?;
82
83    Ok(TokenData { header, claims })
84}