# JWS Operations

Lower-level JSON Web Signature operations for signing and verifying arbitrary payloads. Provides direct access to the signature layer without JWT-specific claim validation, useful for custom payload formats or when you need fine-grained control over the signature process.

## Capabilities

### JWS Encoding

Creates signed JSON Web Signatures from byte payloads with flexible header management and algorithm support.

```python { .api }
class PyJWS:
    def __init__(self, algorithms: list = None, options: dict = None):
        """
        Initialize JWS instance with algorithm whitelist.

        Args:
            algorithms (list): Allowed algorithms for this instance
            options (dict): Default options for verification
        """

    def encode(self, payload: bytes, key, algorithm: str = None,
              headers: dict = None, json_encoder = None,
              is_payload_detached: bool = False, sort_headers: bool = True) -> str:
        """
        Create a JWS signature for the given payload.

        Args:
            payload (bytes): Data to be signed
            key: Private key for signing
            algorithm (str): Signing algorithm
            headers (dict): Additional headers
            json_encoder: Custom JSON encoder
            is_payload_detached (bool): Create detached signature
            sort_headers (bool): Sort header keys

        Returns:
            str: JWS token

        Raises:
            InvalidKeyError: Invalid key for algorithm
            InvalidAlgorithmError: Unsupported algorithm
        """
```

Usage examples:

```python
import jwt

# Basic JWS encoding
jws = jwt.PyJWS()
payload = b'{"user_id": 123, "role": "admin"}'
token = jws.encode(payload, 'secret', algorithm='HS256')

# With custom headers
headers = {'typ': 'JWT', 'kid': 'key-1'}
token = jws.encode(payload, 'secret', algorithm='HS256', headers=headers)

# Detached payload (payload not included in token)
token = jws.encode(payload, 'secret', algorithm='HS256', is_payload_detached=True)
```

### JWS Decoding

Decodes and verifies JSON Web Signatures returning the raw payload bytes without JWT-specific processing.

```python { .api }
class PyJWS:
    def decode(self, jws: str | bytes, key = '', algorithms: list = None,
              options: dict = None, detached_payload: bytes = None) -> bytes:
        """
        Verify JWS signature and return payload.

        Args:
            jws (str | bytes): JWS token to verify
            key: Public key for verification  
            algorithms (list): Allowed algorithms
            options (dict): Verification options
            detached_payload (bytes): Payload for detached signatures

        Returns:
            bytes: Verified payload

        Raises:
            DecodeError: Token format errors
            InvalidSignatureError: Signature verification failed
            InvalidAlgorithmError: Algorithm not allowed
        """

    def decode_complete(self, jws: str | bytes, key = '', algorithms: list = None,
                       options: dict = None, detached_payload: bytes = None) -> dict:
        """
        Decode JWS returning header, payload, and signature.

        Returns:
            dict: {'header': dict, 'payload': bytes, 'signature': bytes}
        """
```

Usage examples:

```python
import jwt
from jwt.exceptions import InvalidSignatureError

jws = jwt.PyJWS()

# Basic decoding
try:
    payload = jws.decode(token, 'secret', algorithms=['HS256'])
    print(f"Payload: {payload.decode('utf-8')}")
except InvalidSignatureError:
    print("Signature verification failed")

# With detached payload
payload = jws.decode(token, 'secret', algorithms=['HS256'], 
                    detached_payload=original_payload)

# Get complete structure
decoded = jws.decode_complete(token, 'secret', algorithms=['HS256'])
print(f"Header: {decoded['header']}")
print(f"Payload: {decoded['payload']}")
```

### Header Operations

Extract and validate JWT headers without signature verification, useful for determining key IDs or algorithm information.

```python { .api }
class PyJWS:
    def get_unverified_header(self, jwt: str | bytes) -> dict:
        """
        Extract JWT header without signature verification.

        Args:
            jwt (str | bytes): JWT token

        Returns:
            dict: JWT header

        Raises:
            DecodeError: Invalid token format
            InvalidTokenError: Invalid header structure
        """
```

Usage example:

```python
import jwt

jws = jwt.PyJWS()

# Extract header to determine key ID
header = jws.get_unverified_header(token)
key_id = header.get('kid')
algorithm = header.get('alg')

print(f"Key ID: {key_id}, Algorithm: {algorithm}")

# Use header info to select appropriate key
if key_id == 'key-1':
    key = get_key_1()
elif key_id == 'key-2':
    key = get_key_2()

payload = jws.decode(token, key, algorithms=[algorithm])
```

### Algorithm Management

Manage cryptographic algorithms for JWS instances with registration and whitelisting capabilities.

```python { .api }
class PyJWS:
    def register_algorithm(self, alg_id: str, alg_obj) -> None:
        """
        Register a new algorithm for use with this JWS instance.

        Args:
            alg_id (str): Algorithm identifier
            alg_obj: Algorithm implementation

        Raises:
            ValueError: Algorithm already registered
            TypeError: Invalid algorithm object
        """

    def unregister_algorithm(self, alg_id: str) -> None:
        """
        Remove an algorithm from this JWS instance.

        Args:
            alg_id (str): Algorithm identifier

        Raises:
            KeyError: Algorithm not registered
        """

    def get_algorithm_by_name(self, alg_name: str):
        """
        Get algorithm implementation by name.

        Args:
            alg_name (str): Algorithm name

        Returns:
            Algorithm object

        Raises:
            NotImplementedError: Algorithm not supported
        """

    def get_algorithms(self) -> list:
        """
        Get list of supported algorithm names.

        Returns:
            list: Algorithm names
        """
```

Usage example:

```python
import jwt

jws = jwt.PyJWS()

# Check supported algorithms
algorithms = jws.get_algorithms()
print(f"Supported: {algorithms}")

# Get algorithm object
hs256 = jws.get_algorithm_by_name('HS256')

# Register custom algorithm (advanced usage)
from jwt.algorithms import Algorithm
class CustomAlgorithm(Algorithm):
    def sign(self, msg, key):
        # Custom signing logic
        pass
    
    def verify(self, msg, key, sig):
        # Custom verification logic
        pass

jws.register_algorithm('CUSTOM', CustomAlgorithm())
```

## Global JWS Functions

Convenience functions that use a global PyJWS instance:

```python { .api }
def get_unverified_header(jwt: str | bytes) -> dict:
    """Extract header without verification (global function)."""

def register_algorithm(alg_id: str, alg_obj) -> None:
    """Register algorithm globally."""

def unregister_algorithm(alg_id: str) -> None:
    """Unregister algorithm globally."""

def get_algorithm_by_name(alg_name: str):
    """Get algorithm by name (global function)."""
```

Usage example:

```python
import jwt

# Using global functions
header = jwt.get_unverified_header(token)
jwt.register_algorithm('CUSTOM', custom_alg)
algorithm = jwt.get_algorithm_by_name('HS256')
```

## Verification Options

JWS verification options are simpler than JWT options:

```python { .api }
# Default JWS verification options
{
    'verify_signature': True  # Verify signature
}
```

Usage example:

```python
# Disable signature verification (dangerous!)
options = {'verify_signature': False}
payload = jws.decode(token, options=options)
```

## Detached Signatures

JWS supports detached signatures where the payload is not included in the token:

```python
import jwt

jws = jwt.PyJWS()
payload = b'sensitive data'

# Create detached signature
token = jws.encode(payload, 'secret', algorithm='HS256', is_payload_detached=True)

# Verify with separate payload
verified = jws.decode(token, 'secret', algorithms=['HS256'], 
                     detached_payload=payload)
```