[Help] PJSIP WebRTC / WSS Registration Fails Despite Correct Credentials

Hi everyone,

we’re trying to use Asterisk 20.6.0 as a middleware to connect SIP.js (WebRTC via WSS) in the browser to our FRITZ!Box SIP trunk.
The goal is:

  • BrowserAsterisk (WSS)FRITZ!Box SIP TrunkOutbound Call
    We want to handle everything via WebRTC/SIP.js without exposing FRITZ!Box credentials to the frontend.

Setup

Environment

  • Asterisk Version: 20.6.0

  • Database: PostgreSQL (Realtime via ODBC)

  • Client: SIP.js 0.21.1

  • Transport: WSS (Port 8089)

  • Browsers Tested: Chrome, Edge

  • Use Case: Outbound calls via FritzBox → Asterisk → Browser


Configuration

pjsip.conf (global)

[global]
type=global
user_agent=Asterisk-KCP
endpoint_identifier_order=auth_username,username,ip


Transport

[transport-wss]
type=transport
protocol=wss
bind=0.0.0.0:8089
allow_reload=yes


Realtime Tables

We’re using PJSIP-Realtime via ODBC (res_odbc_pgsql.conf → working).
Here are the relevant table contents:

ps_auths

id auth_type username realm md5_cred
sip-user md5 User1234 asterisk 65b97a58d1b12c151c6357b9a71b369f

ps_endpoints

id transport aors auth context allow identify_by
sip-user transport-wss sip-user sip-user from-internal opus,ulaw,alaw auth_username

ps_aors

id max_contacts support_path
sip-user 2 yes

Problem

Registration via SIP.js fails. Here’s a snippet from the PJSIP logger:

<--- Received SIP request (477 bytes) from WSS:85.216.xxx.xxx --->
REGISTER sip:sip.dtec-group.de SIP/2.0
Via: SIP/2.0/WSS dsn59428s1on.invalid;branch=z9hG4bK9153338
To: <sip:User1234@sip.dtec-group.de>
From: <sip:User1234@sip.dtec-group.de>;tag=m1mslc52h9
CSeq: 2 REGISTER
Contact: <sip:3tg17l3j@dsn59428s1on.invalid;transport=ws>;expires=600
User-Agent: SIP.js/0.21.1

<--- Transmitting SIP response (473 bytes) --->
SIP/2.0 401 Unauthorized

<--- Received SIP request (753 bytes) from WSS:85.216.xxx.xxx --->
REGISTER sip:sip.dtec-group.de SIP/2.0
Authorization: Digest algorithm=MD5, username="User1234", realm="asterisk", nonce="...", uri="sip:sip.dtec-group.de", response="bed81fbaaf2701922760bc53a948aea3"

[Aug 19 20:56:21] NOTICE[1390753]: res_pjsip/pjsip_distributor.c:673 log_failed_request:
  Request 'REGISTER' from '<sip:User1234@sip.dtec-group.de>' failed - Failed to authenticate


What We’ve Already Tried

  • :white_check_mark: Verified MD5 hash → correct (MD5(User1234:asterisk:Test1234))

  • :white_check_mark: Added endpoint_identifier_order=auth_username,username,ip → works

  • :white_check_mark: Set identify_by=auth_username in ps_endpoints

  • :white_check_mark: Enabled support_path=yes for WebRTC

  • :white_check_mark: WSS transport works, port 8089 open

  • :white_check_mark: Digest response from browser verified as correct

  • :cross_mark: Asterisk still returns 401 Unauthorized


Questions to the Community

  1. Are there known issues with SIP.js + Asterisk Realtime (ODBC) + WebRTC?

  2. Do we need extra configuration in func_odbc.conf or res_odbc.conf for WebRTC auth?

  3. Are there additional parameters required for WSS / WebRTC support?

  4. Could endpoint_identifier_order be problematic when using Realtime + ODBC?


Goal

We want to achieve:

  • Browser using SIP.js → Asterisk (WSS)FRITZ!Box SIP Trunk → Outbound Call

  • FRITZ!Box SIP credentials should never be exposed in the frontend

  • WebRTC should run natively via SIP.js


System Info

Asterisk 20.6.0
PostgreSQL 16
res_odbc_pgsql / Realtime enabled
SIP.js 0.21.1
Transport WSS: 8089


Has anyone successfully implemented a similar setup with WebRTC, SIP.js, and Asterisk Realtime?
Any hints, configs, or working examples would be extremely appreciated! :folded_hands:

Thx in advance

Halim

That is correct. The problem doesn’t happen until the actual authentication is attempted, and, although you have cut the log short, you should get 403 not 401.

Why did you hide the nonce? It’s a random number. If the credentials you provided aren’t real, it would make more sense to obscure the response. Both nonce and response are needed to do a brute force attack. Also, you don’t mention the has that includes the nonce.

Hey david, thx for the quick reply.

Here are the pjsip logger:

== WebSocket connection from ‘85.216.55.145:64326’ for protocol ‘sip’ accepted using version ‘13’
<— Received SIP request (477 bytes) from WSS:85.216.55.145:64326 —>
REGISTER sip:sip.dtec-group.de SIP/2.0
Via: SIP/2.0/WSS qsgp51hs5qda.invalid;branch=z9hG4bK6536853
To: sip:User1234@sip.dtec-group.de
From: sip:User1234@sip.dtec-group.de;tag=o9gc61tqfa
CSeq: 2 REGISTER
Call-ID: 83036pao165gc58cqhq4
Max-Forwards: 70
Contact: sip:ugqh98o4@qsgp51hs5qda.invalid;transport=ws;expires=600
Allow: ACK,CANCEL,INVITE,MESSAGE,BYE,OPTIONS,INFO,NOTIFY,REFER
Supported: outbound, path, gruu
User-Agent: SIP.js/0.21.1
Content-Length: 0

<— Transmitting SIP response (473 bytes) to WSS:85.216.55.145:64326 —>
SIP/2.0 401 Unauthorized
Via: SIP/2.0/WSS qsgp51hs5qda.invalid;rport=64326;received=85.216.55.145;branch=z9hG4bK6536853
Call-ID: 83036pao165gc58cqhq4
From: sip:User1234@sip.dtec-group.de;tag=o9gc61tqfa
To: sip:User1234@sip.dtec-group.de;tag=z9hG4bK6536853
CSeq: 2 REGISTER
WWW-Authenticate: Digest realm=“asterisk”,nonce=“1755640080/c64112855c52d13ae8f5d5e8facd66f4”,opaque=“01e8f3c27b93dc47”,algorithm=MD5,qop=“auth”
Server: Asterisk-KCP
Content-Length: 0

<— Received SIP request (752 bytes) from WSS:85.216.55.145:64326 —>
REGISTER sip:sip.dtec-group.de SIP/2.0
Via: SIP/2.0/WSS qsgp51hs5qda.invalid;branch=z9hG4bK158657
To: sip:User1234@sip.dtec-group.de
From: sip:User1234@sip.dtec-group.de;tag=o9gc61tqfa
CSeq: 3 REGISTER
Call-ID: 83036pao165gc58cqhq4
Max-Forwards: 70
Authorization: Digest algorithm=MD5, username=“User1234”, realm=“asterisk”, nonce=“1755640080/c64112855c52d13ae8f5d5e8facd66f4”, uri=“sip:sip.dtec-group.de”, response=“730adc80cdfdb6fbb922d4f6e5259c81”, opaque=“01e8f3c27b93dc47”, qop=auth, cnonce=“hob9r8lsii3g”, nc=00000001
Contact: sip:ugqh98o4@qsgp51hs5qda.invalid;transport=ws;expires=600
Allow: ACK,CANCEL,INVITE,MESSAGE,BYE,OPTIONS,INFO,NOTIFY,REFER
Supported: outbound, path, gruu
User-Agent: SIP.js/0.21.1
Content-Length: 0

[Aug 19 23:48:01] NOTICE[1431134]: res_pjsip/pjsip_distributor.c:673 log_failed_request: Request ‘REGISTER’ from ‘sip:User1234@sip.dtec-group.de’ failed for ‘85.216.55.145:64326’ (callid: 83036pao165gc58cqhq4) - Failed to authenticate
<— Transmitting SIP response (471 bytes) to WSS:85.216.55.145:64326 —>
SIP/2.0 401 Unauthorized
Via: SIP/2.0/WSS qsgp51hs5qda.invalid;rport=64326;received=85.216.55.145;branch=z9hG4bK158657
Call-ID: 83036pao165gc58cqhq4
From: sip:User1234@sip.dtec-group.de;tag=o9gc61tqfa
To: sip:User1234@sip.dtec-group.de;tag=z9hG4bK158657
CSeq: 3 REGISTER
WWW-Authenticate: Digest realm=“asterisk”,nonce=“1755640081/f18fdbe8da123d96967629c6960faa64”,opaque=“294209b83e81648a”,algorithm=MD5,qop=“auth”
Server: Asterisk-KCP
Content-Length: 0

== WebSocket connection from ‘85.216.55.145:64326’ closed

The users and pass are for testing

The response looks good, unless nc is being reused, on the nonce has gone stale.

david@dhcppc4:~$ echo -n ‘User1234:asterisk:Test1234’ | md5sum
65b97a58d1b12c151c6357b9a71b369f -
david@dhcppc4:~$ echo -n ‘REGISTER:sip:sip.dtec-group.de’ | md5sum
4104247aceb215f8815d4e2ba1ec9281 -
david@dhcppc4:~$ echo -n ‘65b97a58d1b12c151c6357b9a71b369f:1755640080/c64112855c52d13ae8f5d5e8facd66f4:00000001:hob9r8lsii3g:auth:4104247aceb215f8815d4e2ba1ec9281’ | md5sum
730adc80cdfdb6fbb922d4f6e5259c81 -

I’m afraid I don’t know what is wrong.

Could there be invisible characters, like byte order marks?

What is the actual “id” of the endpoint in the database? It needs to match the username.

Thx for testing david, no there are no bytes or invisible charakters, checked it at the database

Hey jcolp,

i’ll put the row of my DB

Sheme of ps_endpoints

[{“idx”:0,“id”:“sip-user”,“transport”:“transport-wss”,“aors”:“sip-user”,“auth”:“sip-user”,“context”:“from-internal”,“disallow”:“all”,“allow”:“opus,ulaw,alaw”,“direct_media”:null,“connected_line_method”:null,“direct_media_method”:null,“direct_media_glare_mitigation”:null,“disable_direct_media_on_nat”:null,“dtmf_mode”:null,“external_media_address”:null,“force_rport”:“yes”,“ice_support”:null,“identify_by”:null,“mailboxes”:null,“moh_suggest”:null,“outbound_auth”:null,“outbound_proxy”:null,“rewrite_contact”:“yes”,“rtp_ipv6”:null,“rtp_symmetric”:“yes”,“send_diversion”:null,“send_pai”:null,“send_rpid”:null,“timers_min_se”:null,“timers”:null,“timers_sess_expires”:null,“callerid”:null,“callerid_privacy”:null,“callerid_tag”:null,“100rel”:null,“aggregate_mwi”:null,“trust_id_inbound”:null,“trust_id_outbound”:null,“use_ptime”:null,“use_avpf”:null,“media_encryption”:null,“inband_progress”:null,“call_group”:null,“pickup_group”:null,“named_call_group”:null,“named_pickup_group”:null,“device_state_busy_at”:null,“fax_detect”:null,“t38_udptl”:null,“t38_udptl_ec”:null,“t38_udptl_maxdatagram”:null,“t38_udptl_nat”:null,“t38_udptl_ipv6”:null,“tone_zone”:null,“language”:null,“one_touch_recording”:null,“record_on_feature”:null,“record_off_feature”:null,“rtp_engine”:null,“allow_transfer”:null,“allow_subscribe”:null,“sdp_owner”:null,“sdp_session”:null,“tos_audio”:null,“tos_video”:null,“sub_min_expiry”:null,“from_domain”:null,“from_user”:“User1234”,“mwi_from_user”:null,“dtls_verify”:null,“dtls_rekey”:null,“dtls_cert_file”:null,“dtls_private_key”:null,“dtls_cipher”:null,“dtls_ca_file”:null,“dtls_ca_path”:null,“dtls_setup”:null,“srtp_tag_32”:null,“media_address”:null,“redirect_method”:null,“set_var”:null,“cos_audio”:null,“cos_video”:null,“message_context”:null,“force_avp”:null,“media_use_received_transport”:null,“accountcode”:null,“user_eq_phone”:null,“mwi_subscribe_replaces_unsolicited”:null,“deny”:null,“permit”:null,“contact_deny”:null,“contact_permit”:null,“contact_user”:null,“preferred_codec_only”:null,“asymmetric_rtp_codec”:null,“rtcp_mux”:null,“allow_overlap”:null,“refer_blind_progress”:null,“notify_early_inuse_ringing”:null,“max_audio_streams”:null,“max_video_streams”:null,“webrtc”:“yes”,“dtls_fingerprint”:null,“incoming_mwi_mailbox”:null,“uniqueid”:“sip-user”,“type”:“endpoint”}]

Sheme of ps_auths

[{“idx”:0,“id”:“sip-user”,“auth_type”:“userpass”,“nonce_lifetime”:null,“md5_cred”:null,“password”:“Test1234”,“realm”:“asterisk”,“username”:“User1234”,“uniqueid”:“sip-user”,“type”:“auth”}]

Sheme of ps_aors

[{“idx”:0,“id”:“sip-user”,“contact”:null,“max_contacts”:2,“remove_existing”:null,“qualify_frequency”:null,“authenticate_qualify”:null,“maximum_expiration”:null,“minimum_expiration”:null,“outbound_proxy”:null,“support_path”:“yes”,“qualify_timeout”:null,“voicemail_extension”:null,“uniqueid”:“sip-user”,“type”:“aor”}]

Here you can see, that i used always for the id’s for testing: “sip-user”

I defined all of the tables type like aor, endpoint or auth

The username is always: User1234 and the Pass: Test1234

i’m confused, why it didn’t match and don’t get the Authentication for REGISTER on Asterisk.

Thx for any help in advance

Halim

Because it would be looking for “User1234” in the database, and not “sip-user”. The “id” needs to match either the From username, or the authentication username.

Tested and it worked fine! Now im REGISTERED

I spent over 24 hours for finding the solution, thank you so much jcolp :clap:

I’ll test now to start a call over WSS. When i found andything, is ok to ask you before spent another 24 hours :smiley:

Thx

Halim

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.