# `PushX.Token`
[🔗](https://github.com/cignosystems/pushx/blob/v0.11.0/lib/push_x/token.ex#L1)

Token validation for push notification device tokens.

Validates token format before sending to avoid unnecessary API calls.
Validation is fast (microseconds) and catches obvious errors early.

## APNS Tokens (iOS/macOS/Safari)

APNS device tokens are 64 hexadecimal characters (32 bytes).
Safari web push tokens use the same format.
Example: `"a1b2c3d4e5f6...64 hex chars total"`

## FCM Tokens (Android/Web)

FCM registration tokens are variable length:
- Mobile tokens: typically 140-250 characters
- Web tokens: typically 50-200 characters
They contain alphanumeric characters, hyphens, underscores, and colons.
Example: `"dGVzdC10b2tlbi1mb3ItZmNt..."`

## Usage

    iex> PushX.Token.valid?(:apns, "a1b2c3d4" <> String.duplicate("0", 56))
    true

    iex> PushX.Token.valid?(:apns, "too-short")
    false

    iex> PushX.Token.validate(:apns, "invalid")
    {:error, :invalid_length}

# `provider`

```elixir
@type provider() :: :apns | :fcm
```

# `token`

```elixir
@type token() :: String.t()
```

# `validation_error`

```elixir
@type validation_error() :: :empty | :invalid_format | :invalid_length
```

# `error_message`

```elixir
@spec error_message(provider(), validation_error()) :: String.t()
```

Returns a human-readable error message for validation errors.

# `valid?`

```elixir
@spec valid?(provider(), token()) :: boolean()
```

Returns `true` if the token is valid for the given provider.

## Examples

    iex> PushX.Token.valid?(:apns, String.duplicate("a", 64))
    true

    iex> PushX.Token.valid?(:apns, "invalid")
    false

# `validate`

```elixir
@spec validate(provider(), token()) :: :ok | {:error, validation_error()}
```

Validates a device token and returns `:ok` or `{:error, reason}`.

## Examples

    iex> PushX.Token.validate(:apns, String.duplicate("a", 64))
    :ok

    iex> PushX.Token.validate(:apns, "")
    {:error, :empty}

    iex> PushX.Token.validate(:apns, "too-short")
    {:error, :invalid_length}

    iex> PushX.Token.validate(:apns, String.duplicate("g", 64))
    {:error, :invalid_format}

# `validate!`

```elixir
@spec validate!(provider(), token()) :: :ok
```

Validates a token and raises `ArgumentError` if invalid.

## Examples

    iex> PushX.Token.validate!(:apns, String.duplicate("a", 64))
    :ok

    iex> PushX.Token.validate!(:apns, "invalid")
    ** (ArgumentError) Invalid APNS token: invalid_length

---

*Consult [api-reference.md](api-reference.md) for complete listing*
