103

What is the equivalent of

curl -u username:password ...

in PowerShell's Invoke-RestMethod? I tried this:

$securePwd = ConvertTo-SecureString "password" -AsPlainText -Force
$credential = New-Object System.Management.Automation.PSCredential ($username, $securePwd)

Invoke-RestMethod -Credential $credential ...

but it returns 401, Unauthorized.

4
  • 1
    Reading the comments below with various multi-line solutions that work in some scenarios with caveats, it saddens me that The One Great Scripting Language from Microsoft has so much discussion, but no simple equivalent, for "curl -u username:password". Sigh. My solution was download curl.exe. Commented Mar 16, 2018 at 19:33
  • @pettys yeah, sure, much consulting... btw curl is included in windows for quite some time now(no, not the posh alias) Commented May 16, 2019 at 12:02
  • Good to know! I see now that curl.exe was added to C:\Windows\System32 in Win 10 build 17063. @JaquelineVanek, I'm not sure what to make of all your comment, but I'm glad to know it's there now. Commented May 16, 2019 at 15:54
  • 1
    Have you tried to just add -Authentication Basic as a parameter to Invoke-RestMethod ? The rest being identical, it works for me just fine. Context: I am pulling the creds from env variables and querying Zendesk HelpCenter API. Commented Mar 25, 2021 at 9:10

9 Answers 9

151

This is the only method that worked for me so far:

$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $username,$password)))

Invoke-RestMethod -Headers @{Authorization=("Basic {0}" -f $base64AuthInfo)} ...

But I don't believe there isn't a better way.

Sign up to request clarification or add additional context in comments.

1 Comment

Worked for us after simplifying the GetBytes parameter to just '("username:password")'. Thanks!
26

I'm not sure why the -Credential parameter isn't working in your case, but it works with the httpbin service.

You can try this:

$pwd = ConvertTo-SecureString "MyPassword" -AsPlainText -Force
$cred = New-Object Management.Automation.PSCredential ('PsUser', $pwd)

Invoke-RestMethod 'http://httpbin.org/basic-auth/PsUser/MyPassword' -cred $cred

Edit: As noted in the comments, this method will not send the Authorization header on the initial request. It waits for a challenge response then re-sends the request with the Authorization header. This will not work for services that require credentials on the initial request.

6 Comments

How is that different from the snippet in the question?
I was affirming that it does work for basic authentication, and provided a URL to test it against. I wouldn't want users to come to this question looking for how to use basic auth and be told that -Credential does not work. It clearly does in the example I provided. There must be something in your situation that is causing it to break.
Ah sorry I missed that you are suggesting testing against a specific URL. In my case, curl works and my "manual" method of providing Authorization HTTP header works too, it's just the Credential parameter that doesn't. Don't you know what it does, internally? Does it just add the same HTTP header?
@Borek After checking against httpbin.org while running WireShark, I see that using -Credential does not add the Authorization header in the first request. Httpbin.org responds with a 401 then PowerShell sends a second request that does have the Authorization header. Httpbin.org responds with a 200 after the second request. As far as I can tell, your method is the only way to send the header on the first request.
I just found this blog entry at weblog.west-wind.com/posts/2010/Feb/18/… that talks about the same issue with HttpWebRequest which PowerShell probably uses to send HTTP requests.
|
23
#Requires -Version 6
$Uri = 'https://httpbin.org/basic-auth/user/pass'
# use "user" and "pass" when prompted for credentials
$Credential = Get-Credential
Invoke-RestMethod -Uri $Uri -Authentication Basic -Credential $Credential

7 Comments

There are a lot of very old answers here, but this is the correct modern answer to use. Provide a credential object and specify -Authentication Basic for easy basic Auth in PowerShell.
But that doesn't seem to work in Windows Powershell?
@NickG obviously, as stated #Requires -Version 6
@BorisVerkhovskiy Update-Help; Get-Help Get-Credential -Examples or just learn.microsoft.com/en-us/powershell/module/… ex4
@BorisVerkhovskiy alternative notation $cred = [pscredential]::new($StringUserName, $SecureStringPassword) you might wanna have a look at how the 'SecureString' thingie works
|
14

It appears you should combine methods when they fail independently.

Create the credential and add it to the request.

Create the header and add it to the request.

$username = "username";
$password = ConvertTo-SecureString –String "password" –AsPlainText -Force
$credential = New-Object –TypeName "System.Management.Automation.PSCredential" –ArgumentList $username, $password

$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $username,$password)))

$getProjectUri = "yourUri"
Invoke-RestMethod -Method Get -Uri $getProjectUri -Headers @{Authorization = "Basic $base64AuthInfo" } -Credential $credential -ContentType "application/json"

3 Comments

should? I feel there's a citation missing here
Not sure how to handle this, I say should because in cases some implementations seem to need both credentials on the first request as Borek and @Rynant have found. So sometimes, depending on the server being called you may need to combine the methods.
Confirming that combining solved downloading artifacts from VSO. Thnx.
6

This version works with Get-Credential's PSCredential object. It also works cross-platform in PowerShell 6.0. It does this by avoiding use of BSTR calls, which are sometimes suggested when attempting to extract the password from PSCredential.

$creds = Get-Credential
$unsecureCreds = $creds.GetNetworkCredential()
$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $unsecureCreds.UserName,$unsecureCreds.Password)))
Remove-Variable unsecureCreds

Invoke-RestMethod -Headers @{Authorization=("Basic {0}" -f $base64AuthInfo)} ...

Comments

6

You basically need to pass the username and password pair to Invoke-RestMethod as an encoded credentials variable.

What worked for me was the following:

$USERNAME = 'user'
$PASSWORD = 'password'
$IDP_URL = 'example.com/token'


$credPair = "$($USERNAME):$($PASSWORD)"
$encodedCredentials = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes($credPair))

$parameters = @{
    Uri         = $IDP_URL
    Headers     = @{ 'Authorization' = "Basic $encodedCredentials" }
    Method      = 'POST'
    Body        = '...'
    ContentType = '...'
}

Invoke-RestMethod @parameters

Note how you can extract the request parameters into $parameters to avoid bloating your command.

Comments

5

I've found that using the -WebSession parameter works, if you pre-create a WebRequestSession object with credentials. I won't rehash how to create a PS Credential object, as that's already been covered in other answers.

$WebSession = New-Object -TypeName Microsoft.PowerShell.Commands.WebRequestSession -Property @{Credentials=$Credential}
Invoke-RestMethod -Uri "your_URI" -WebSession $WebSession

This approach sends the auth header on the first call, so avoids the 401 response.

Incidentally, this approach can also be used to set proxy details (which don't work properly in all versions of PS when specified using the parameters), and handles cookies if your API requires that.

Comments

2

I know this is a really old question, but I wanted to share an update somewhere. None of the posts I was finding for Basic Auth with PowerShell were working for me. After much trial-and-error and reading through the MS Docs I found that I needed to use the -AllowUnencryptedAuthentication parameter because I was connecting using http. I also had to upgrade my PS version to get access to the parameter.

From the description of the parameter: "Allows sending of credentials and secrets over unencrypted connections. By default, supplying Credential or any Authentication option with a Uri that does not begin with https:// will result in an error and the request will abort to prevent unintentionally communicating secrets in plain text over unencrypted connections. To override this behavior at your own risk, supply the AllowUnencryptedAuthentication parameter."

Comments

0

I spent a few days having no luck with any of the above examples. Eventually I worked out I needed to specify the Method of Post. e.g.:

$request =  Invoke-WebRequest -Method Post -Uri "https://www.emea-api.morningstar.com/token/oauth" -Headers @{accept='*/*';Authorization='Basic bWFy...encoded username:password...='};

-mobailey

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.