6

I am using ngrok to expose my localhost on a raspberry pi, and ngrok is password protected. I am using Django on another computer outside my network to access a webpage(simple server) on this raspberry pi. I don't want to manually type in the username and password to ngrok.

How can I automatically fill in the ngrok user/password, which is a popup in chrome asking for user and password?

What I've tried: I first tried using JS in my template, just using a fetch request: https://user:password@myngrokdomain.ngrok.io but chrome threw an error in the console saying I can't pass in credentials in plain text like this, rightfully so...

I then tried to use python requests:

    UN= "myuser"
    PWD = "mypassword"
    loginURL = "https://myngrokdomain.ngrok.io"
    client = requests.session()
    login_data = dict(username=UN, password=PWD,)
    r = client.post(loginURL, data=login_data)

This returned a 401 access denied

r.headers + r.reason returns: 401 Unauthorized Unauthorized {'Content-Length': '16', 'Content-Type': 'text/plain', 'Www-Authenticate': 'Basic realm="ngrok"', 'Date': 'Tue, 16 Mar 2021 15:22:15 GMT'}

MattG
  • 1,682
  • 5
  • 25
  • 45

3 Answers3

5

The authentication method used by ngrok is called HTTP Basic Auth. To use it with the requests library you pass login and password as a tuple in the auth argument:

r = client.post(loginURL, auth=(UN, PWD))

Docs: Basic Authentication — Requests

Igonato
  • 10,175
  • 3
  • 35
  • 64
  • Thanks @Igonato. Where did you find, or how did you know, that ngrok used this type of authentication? – MattG Mar 16 '21 at 20:13
  • @MattG The `Www-Authenticate` header specifies the authentication method that should be used to gain access to a resource, it says Basic right in it. Also, when you see the native browser popup it's Basic Auth. And passing credentials in a URL like user:pass@example.com - that's also only works for Basic Auth – Igonato Mar 17 '21 at 03:15
1

Try doing a get on the login page first. Perhaps it's setting some cookies that it expects to be present on the post :

    UN= "myuser"
    PWD = "mypassword"
    loginURL = "https://myngrokdomain.ngrok.io"
    client = requests.session()
    login_data = dict(username=UN, password=PWD,)
    client.get(loginURL )
    r = client.post(loginURL, data=login_data)
Belhadjer Samir
  • 1,461
  • 7
  • 15
0

You need to distinguish whether you're making the request from a browser or from a server application.

Browser

If you're doing it from a browser you're hitting a CORS issue and ngrok doesn't support that when providing --auth. From the docs:

you cannot use ngrok's -auth option. ngrok's http tunnels allow you to specify basic authentication credentials to protect your tunnels. However, ngrok enforces this policy on all requests, including the preflight OPTIONS requests that are required by the CORS spec. In this case, your application must implement its own basic authentication

In this case, your only option is to implement authentication in your application instead of using ngrok's --auth.

Server

If you're sending the request from a server application you won't get into any CORS issue but you need to provide the Basic Authentication credentials properly.

Say you have your application exposed via ngrok at http://myapp.ngrok.io protected via --auth user:pass.

In plain Node.js you would do something like this:

const http = require('http')

http.get('http://myapp.ngrok.io', { auth: 'user:pass' }, res => {
  const chunks = []

  res.on('data', chunk => {
    chunks.push(chunk)
  })

  res.on('end', () => {
    console.log(Buffer.concat(chunks).toString('utf-8'))
  })
})

Note that to hit the https url you would use Node's https module instead of http, or a higher level library that handles that for you, like node-fetch.

In Python you can do something similar and this question will probably get you on the right path.

Simone
  • 3,607
  • 1
  • 31
  • 37