try hiccup

SIP 403 Forbidden

Short version: a 403 is a policy refusal, not an authentication failure. The server understood exactly who you are and what you asked for, and said no. Passwords are the last thing to check — the trunk ACL, the caller ID, the destination class and the account balance come first.

What 403 actually means

RFC 3261 section 21.4.4 is short and unusually final: the server understood the request but is refusing to fulfil it, and the request should not be repeated. That last clause is what separates 403 from almost every other 4xx. A 401 or 407 is an invitation to try again with credentials; a 403 is a verdict. Retrying the same request, with or without authentication, is expected to produce the same answer, because the refusal is about policy — who is calling, from where, to where, on whose account — not about anything you can fix inside the message.

One consequence worth internalising: when a carrier sends 403, somewhere a rule matched. Your job in the trace is to work out which rule, and the response itself rarely tells you directly. The reason phrase and any Reason header are the closest thing to a confession you will get.

What actually causes it

The source IP is not on the trunk ACL

The most common cause on IP-authenticated trunks, by a distance. The carrier admits signalling only from the addresses provisioned on the trunk, and your INVITE arrived from somewhere else: a new SBC, a second WAN that took over after a failover, a NAT whose public address changed overnight, or simply a second signalling interface nobody registered with the carrier. Every call fails identically and instantly, which is itself diagnostic — auth problems tend to be intermittent, ACL problems are total.

The caller ID was screened out

Carriers increasingly refuse calls whose calling number is not one they can attribute to your account — anti-spoofing policy, and in some markets a regulatory obligation. If the number in From or P-Asserted-Identity is not on the trunk's authorised list, the INVITE bounces with 403 before routing is even attempted. This is the classic "calls with our main number work, calls presenting the customer's own number fail" pattern. RFC 8224 defines dedicated codes for Identity-header failures (428, 436, 438), but plenty of carriers just send 403 for anything CLI-related.

The destination is barred

International, premium-rate and satellite prefixes are blocked by default on many trunks, either as a class-of-service setting or as a fraud lock that engaged after unusual traffic. Cloud carriers formalise this: Twilio, for example, answers 403 when the destination country is not enabled in the account's geographic permissions. If national calls work and one prefix family fails, this is where to look — not at the SIP at all.

The money ran out

RFC 3261 reserves 402 Payment Required for future use, so almost nobody sends it. The field reality is that an empty prepaid balance, an expired card or a suspended account surfaces as 403 on every outbound call. Sudden onset at an odd hour, all destinations affected, inbound often still working — that shape is a billing event, and no amount of packet analysis will fix it.

Failed authentication dressed up as 403

Some stacks answer a wrong digest response with 403 instead of issuing a fresh challenge — Asterisk's old chan_sip famously replied "403 Forbidden (Bad auth)". So a 403 that arrives immediately after your credentialed retry of a 401 is, despite everything above, probably an auth failure after all. The sequence in the trace tells you which world you are in.

403 with correct credentials

This is the ticket that keeps re-opening: registration succeeds, the password is demonstrably right, and calls still get 403. It is not a contradiction. Registration and call authorisation are separate decisions — the registrar confirmed who you are, and the proxy then declined what you asked to do with that identity. Check whether the account is allowed to call that destination class, whether the From user is required to match the authenticated username (many switches enforce this and 403 anything else), and whether the trunk is IP-authenticated on top of digest, in which case the ACL section above applies even though credentials exist. If the 403 follows a 401/407 challenge in the same transaction, re-verify the boring things: auth username versus SIP username, the realm, and a password that survived every provisioning system between you and the device without a character being eaten.

403 vs 401/407 vs 603

A 401 Unauthorized or 407 Proxy Authentication Required carries a WWW-Authenticate or Proxy-Authenticate challenge and expects a retry — it is part of the normal call flow in most deployments, not a failure. A 403 carries no challenge and expects silence. 603 Decline is different again: it is a global-failure response meaning the callee — a human, or policy acting for one — refused this particular call, whereas 403 is the network refusing to carry it. The distinction blurs at PSTN gateways, because RFC 3398 maps both 403 and 603 to Q.850 cause 21, "call rejected", in the SIP-to-ISUP direction; coming back the other way, cause 21 becomes 403. If your 403 carries Reason: Q.850;cause=21, the refusal happened somewhere in the telephone network, not in anyone's SIP policy.

Carrier habits worth knowing

The reason phrase after "403" is free text and carriers use it: "Forbidden — Geo blocked", "CLI not allowed", "Out of credit". None of it is standardised and all of it is worth reading. Some carriers send 403 where you would expect 503 — channel limit reached, trunk capacity exceeded — so a burst of 403s under load is not always policy. Automated fraud engines produce 403s with a signature: they begin at a precise moment, affect specific prefixes, and often lift after a phone call to the carrier. And where a call crossed into the PSTN, expect the 403 to be an RFC 3398 translation of a Q.850 cause (21 call rejected, or 57 bearer capability not authorized) rather than a decision any SIP element made.

What to check in the trace

  1. Establish which element minted the 403. Compare the source address of the response and its Via stack against the path — a 403 from your own proxy is a local policy problem, not a carrier one.
  2. Look for a 401/407 earlier in the same transaction. Challenge, credentialed retry, then 403 means the credentials were rejected. A bare 403 with no challenge means policy.
  3. Read the reason phrase and any Reason header. A Q.850;cause= value moves the investigation into the PSTN.
  4. Check the numbers: what was in From, P-Asserted-Identity and Remote-Party-ID, and is each one provisioned on the trunk? Retest with the trunk's own main number as CLI.
  5. Check the source IP the INVITE actually left from — after an SBC failover or on a dual-WAN edge it is not always the one you think.
  6. Test a boring destination: national, geographic, non-premium. If that works, you are looking at destination barring, not a broken trunk.
  7. Note the timing. A 403 in a few milliseconds is an edge rule (ACL, CLI screen); one that takes a second or two suggests a downstream lookup — balance, routing, or a refusal relayed from beyond the first hop.

hiccup separates challenge–retry authentication flows from terminal refusals, shows which hop in the path produced the 403, and surfaces reason phrases and Q.850 causes as findings next to the ladder. Self-hosted, free for individual users.

upload a trace