SIP 403
SIP 403 Forbidden in Asterisk
A 403 is a refusal, not a failure. The far end understood exactly what you asked for and decided you were not allowed to ask. That makes it one of the more informative rejections: the problem is nearly always identity, and identity is only ever a credential or an IP address.
What it looks like in the log
[2026-08-17 11:02:41] VERBOSE[9912] res_pjsip_logger.c: <--- Received SIP response (712 bytes) --->
SIP/2.0 403 Forbidden
Via: SIP/2.0/UDP 41.72.10.8:5060;branch=z9hG4bKPj1d0e77
From: <sip:12025550118@pbx.example.net>;tag=c41a09
To: <sip:12025550143@sip.provider.net>;tag=as7712bb
CSeq: 102 INVITE
What it means
Unlike a 401 or 407, a 403 does not invite you to try again with credentials. It is final. The far end has already decided who you are - or failed to work it out - and the answer is no.
The direction matters here too. A 403 received on an outbound INVITE is your provider rejecting you. A 403 sent by Asterisk on an inbound request is usually res_pjsip_endpoint_identifier_ip failing to match the source to any endpoint, which Asterisk also logs as a separate warning line worth finding.
Most common causes
-
01The server's public IP is not on the provider's allowlist
The single most common cause on IP-authenticated trunks. It appears the moment the box changes address: a new VPS, a failover, a NAT rebuild, or an ISP that quietly rotated a dynamic IP overnight. The trunk worked yesterday and nothing in the config changed, which is exactly what makes it confusing. On FreePBX this is the classic "trunk stopped working, nothing was touched" report - the fix is at the carrier portal, not in the trunk settings.
-
02Credentials that are correct but not being sent
A trunk configured with a username and password that Asterisk never offers, because the
outbound_authsection is not referenced from the trunk, looks identical to wrong credentials from the far end. -
03The From or contact user does not match the account
Many carriers reject a call whose From header presents a number not provisioned on that account. The credentials pass and the IP is right, but the caller ID is one the trunk is not permitted to use, and the rejection is a 403.
-
04Inbound traffic from an unknown source
Asterisk sending the 403 means it could not identify the peer. Either the source IP is not in any
identifysection, or the request arrived on a transport the endpoint does not have configured. -
05Account suspended or unpaid
Worth ruling out early, because no amount of config reading will find it. Carriers commonly express a suspended account as a blanket 403 on every INVITE.
How to tell which one it is
Read the To and From headers on the rejected INVITE and check whether the number in From is one the account is allowed to present. Then check what public IP the box is actually sending from, which is not always the one you think - a NAT-ed PBX that has external_media_address set but not external_signaling_address will present the wrong one.
If the 403 is being sent by Asterisk rather than received, look for a warning line near it. An unmatched inbound request logs its source address, which tells you immediately whether the problem is a missing identify section or traffic from somewhere you did not expect at all.
How to fix it
-
Confirm the outbound IP with the provider
Compare the address the provider has allowlisted against what the box actually presents. If the PBX is behind NAT, set
external_signaling_addressso the SIP headers carry the public address rather than the private one. -
Check the auth section is actually attached
On a trunk, the
outbound_auth=line on the endpoint must name the auth section. An auth section that exists but is never referenced is silently ignored, and no error is logged for it. -
Present a caller ID the account owns
If the carrier rejects unowned numbers, set the outbound caller ID on the trunk to a provisioned DID rather than passing the internal extension straight through.
-
Add an identify section for inbound traffic
For a 403 that Asterisk is sending, add the carrier's signalling IPs to a
type=identifysection pointing at the trunk endpoint, so inbound requests match before authentication is even attempted.