RestAPi, Clientsecret, ClientId med Basic Auth

Permalänk

RestAPi, Clientsecret, ClientId med Basic Auth

Hej

Jag ska prata med ett API, beskrivningen jag har är följande:

The Customer uses HTTP Authorization header to pass authentication information to all endpoints. The Authorization header has the following format:
Authorization: Basic ClientID:ClientSecret (base64token encoded)
The HTTP request containing an Authorization header is shown below:

GET https://api.*****se/bananer/v1/health HTTP/1.1

Authorization Basic *****************************

Detta borde vara enkelt och är det säkert för en som jobbar med sånt här, men jag får det ej att fungera. (det blir en timeout)
Jag vill ha lösningen i C# eller Powershell, jag försökte med C# och javascript.

C# försök, kod baserad på https://gist.github.com/bryanbarnard/8102915#file-simplehttpc...

using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Net.Http; using System.Net; namespace HTTP_Test { class program { static void Main() { Task t = new Task(HTTP_GET); t.Start(); Console.ReadLine(); } static async void HTTP_GET() { var TARGETURL = "https://api.*****.se/bananer/v1/health"; /// The client information used to get the OAuth Access Token from the server. string clientId = "***********"; string clientSecret = "************"; Console.WriteLine("GET: + " + TARGETURL); // ... Use HttpClient. HttpClient client = new HttpClient(); var byteArray = Encoding.ASCII.GetBytes(clientId + ":" + clientSecret); client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Basic", Convert.ToBase64String(byteArray)); HttpResponseMessage response = await client.GetAsync(TARGETURL); HttpContent content = response.Content; // ... Check Status Code Console.WriteLine("Response StatusCode: " + (int)response.StatusCode); // ... Read the string. string result = await content.ReadAsStringAsync(); // ... Display the result. if (result != null && result.Length >= 50) { Console.WriteLine(result.Substring(0, 50) + "..."); } } } }

Javascript försök

<div> <div id="response"> </div> <input type="button" class="btn btn-primary" value="Call Web API" onclick="javascript:CallWebAPI();" /> <script> function CallWebAPI() { // New XMLHTTPRequest var request = new XMLHttpRequest(); request.open("GET", "https://api.*****.se/bananer/v1/health", false); var clientId = '*************'; var clientSecret = '*************'; var encodedData = window.btoa(clientId + ':' + clientSecret); var authorizationHeaderString = 'Authorization: Basic ' + encodedData; alert(authorizationHeaderString); request.setRequestHeader("Authorization", authorizationHeaderString); request.send(); // view request status alert(request.status); response.innerHTML = request.responseText; } </script>

Någon som har något tips.. Det hade varit enkelt om jag hade kunnat lämnat ut lösenord, men livet är inte alltid enkelt..

Permalänk
Medlem
Skrivet av lillaankan_i_dammen:

Hej

Jag ska prata med ett API, beskrivningen jag har är följande:

The Customer uses HTTP Authorization header to pass authentication information to all endpoints. The Authorization header has the following format:
Authorization: Basic ClientID:ClientSecret (base64token encoded)
The HTTP request containing an Authorization header is shown below:

GET https://api.*****se/bananer/v1/health HTTP/1.1

Authorization Basic *****************************

Detta borde vara enkelt och är det säkert för en som jobbar med sånt här, men jag får det ej att fungera. (det blir en timeout)
Jag vill ha lösningen i C# eller Powershell, jag försökte med C# och javascript.

C# försök, kod baserad på https://gist.github.com/bryanbarnard/8102915#file-simplehttpc...

using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Net.Http; using System.Net; namespace HTTP_Test { class program { static void Main() { Task t = new Task(HTTP_GET); t.Start(); Console.ReadLine(); } static async void HTTP_GET() { var TARGETURL = "https://api.*****.se/bananer/v1/health"; /// The client information used to get the OAuth Access Token from the server. string clientId = "***********"; string clientSecret = "************"; Console.WriteLine("GET: + " + TARGETURL); // ... Use HttpClient. HttpClient client = new HttpClient(); var byteArray = Encoding.ASCII.GetBytes(clientId + ":" + clientSecret); client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Basic", Convert.ToBase64String(byteArray)); HttpResponseMessage response = await client.GetAsync(TARGETURL); HttpContent content = response.Content; // ... Check Status Code Console.WriteLine("Response StatusCode: " + (int)response.StatusCode); // ... Read the string. string result = await content.ReadAsStringAsync(); // ... Display the result. if (result != null && result.Length >= 50) { Console.WriteLine(result.Substring(0, 50) + "..."); } } } }

Javascript försök

<div> <div id="response"> </div> <input type="button" class="btn btn-primary" value="Call Web API" onclick="javascript:CallWebAPI();" /> <script> function CallWebAPI() { // New XMLHTTPRequest var request = new XMLHttpRequest(); request.open("GET", "https://api.*****.se/bananer/v1/health", false); var clientId = '*************'; var clientSecret = '*************'; var encodedData = window.btoa(clientId + ':' + clientSecret); var authorizationHeaderString = 'Authorization: Basic ' + encodedData; alert(authorizationHeaderString); request.setRequestHeader("Authorization", authorizationHeaderString); request.send(); // view request status alert(request.status); response.innerHTML = request.responseText; } </script>

Någon som har något tips.. Det hade varit enkelt om jag hade kunnat lämnat ut lösenord, men livet är inte alltid enkelt..

Svårt att kunna testa utan att ha tillgång till koden, men din JavaScript känns väldigt föråldrad. Får du något som helst fel meddeande i consolen om ditt response? Tänker statuskod etc.

Testa anpassa denna kod för dina credentials och se om du får ut nåt. Lägger en console.log för response och även eventuellt fel.
Kan anpassa det för C# om jag vet vad du får ut för typ av fel.

(async function() { const apiUrl = "https://api.*****.se/bananer/v1/health"; const clientId = "*************"; const clientSecret = "*************"; const encodedData = window.btoa(`${clientId}:${clientSecret}`); let headers = new Headers(); headers.append("Authorization", `Basic ${encodedData}`); try { const res = await fetch(apiUrl, { method : 'GET', headers : headers, }); const data = await res.json(); console.log(data); } catch (err) { console.log(err); } })();

Permalänk
Skrivet av zaibuf:

Svårt att kunna testa utan att ha tillgång till koden, men din JavaScript känns väldigt föråldrad. Får du något som helst fel meddeande i consolen om ditt response? Tänker statuskod etc.

Testa anpassa denna kod för dina credentials och se om du får ut nåt. Lägger en console.log för response och även eventuellt fel.
Kan anpassa det för C# om jag vet vad du får ut för typ av fel.

(async function() { const apiUrl = "https://api.*****.se/bananer/v1/health"; const clientId = "*************"; const clientSecret = "*************"; const encodedData = window.btoa(`${clientId}:${clientSecret}`); let headers = new Headers(); headers.append("Authorization", `Basic ${encodedData}`); try { const res = await fetch(apiUrl, { method : 'GET', headers : headers, }); const data = await res.json(); console.log(data); } catch (err) { console.log(err); } })();

Tackar för hjälpen nu har jag bättre kod att utgå ifrån. Jag får det ej att fungera men jag har bättre kod att utgå ifrån när jag kan kontakta supporten. Det är lite känsligt att kontakta supporten hos en kund kring bristande kunskaper om grundläggande saker, trots man ej har sålt in något med webbutvecklingen att göra. Min javascript kunskaper baseras från midijukeboxen i javascript som jag gjorde runt 1997.

Felet jag fick i chrome var:
GET https://api.*.se/v1/health net::ERR_CONNECTION_RESET
CallWebAPI @ test.html:14
onclick @ test.html:44
test.html:23 TypeError: Failed to fetch

Jag förstår inte hur man skulle anropa din kod ovanför så jag skrev om den såhär:

async function CallWebAPI() { alert("running"); const apiUrl = "*********"; const clientId = '***********'; const clientSecret = '*********'; const encodedData = window.btoa(`${clientId}:${clientSecret}`); let headers = new Headers(); headers.append("Authorization", `Basic ${encodedData}`); try { const res = await fetch(apiUrl, { method : 'GET', headers : headers, }); const data = await res.json(); console.log(data); } catch (err) { console.log(err); } };

Permalänk
Medlem

En GET-operation, där URL:en du anger är skyddad av Basic Authentication och där du låter bli att ange Authorization-headern ska ge HTTP Status 401 tillbaka:

HTTP/1.1 401 Unauthorized Date: Mon, 04 Feb 2014 16:50:53 GMT WWW-Authenticate: Basic realm="WallyWorld"

(exemplet taget från RFC 7617).

Nästan alla webbläsare skickar i det läget upp en liten ful dialogruta för att ange användarnamn och lösenord, i ditt fall det som benämns ClientId och ClientSecret. Det lättaste sättet att testa om API:et fungerar är alltså att klistra in URL:en i webbläsarens adressrad och trycka på enter. Gärna med webbläsarens debug-mode igång så att du kan se nätverkstrafiken. Det förväntade beteendet är alltså att du ska se ovanstående svar i debug-läget och att du ska få inloggningsdialogen i det ordinarie webbläsar-användargränssnittet. Med rätt användarnamn och lösenord angivet i dialogrutan ska resultatet komma tillbaka i webbläsarfönstret.

Samma sak går även att göra med curl eller liknande verktyg, vilket kanske är lättare att dokumentera när du hör av dig till supporten (eller skriver nya inlägg här).

Det låter på din felbeskrivning som om servern helt enkelt inte svarar - jag gissar alltså att webbläsaren inte ens lyckas skicka sin GET-request eller i alla fall inte får något vettigt svar. Om jag har rätt i att uppkopplingen inte lyckas kan det vara dags att börja misstänka brandväggar. I det läget plockar man fram Wireshark och kollar hur TCP-anslutningen beter sig, men det kräver grundläggande kunskap om TCP.

Några andra noteringar:
- Alla HTTP-headers har kolon efter sig, det har inte exemplet i ditt ursprungsinlägg
- En kommentar nämner OAUTH, men det är med stor sannolikhet en missuppfattning från din sida

Permalänk
Medlem
Skrivet av lillaankan_i_dammen:

Tackar för hjälpen nu har jag bättre kod att utgå ifrån. Jag får det ej att fungera men jag har bättre kod att utgå ifrån när jag kan kontakta supporten. Det är lite känsligt att kontakta supporten hos en kund kring bristande kunskaper om grundläggande saker, trots man ej har sålt in något med webbutvecklingen att göra. Min javascript kunskaper baseras från midijukeboxen i javascript som jag gjorde runt 1997.

Felet jag fick i chrome var:
GET https://api.*.se/v1/health net::ERR_CONNECTION_RESET
CallWebAPI @ test.html:14
onclick @ test.html:44
test.html:23 TypeError: Failed to fetch

Jag förstår inte hur man skulle anropa din kod ovanför så jag skrev om den såhär:

async function CallWebAPI() { alert("running"); const apiUrl = "*********"; const clientId = '***********'; const clientSecret = '*********'; const encodedData = window.btoa(`${clientId}:${clientSecret}`); let headers = new Headers(); headers.append("Authorization", `Basic ${encodedData}`); try { const res = await fetch(apiUrl, { method : 'GET', headers : headers, }); const data = await res.json(); console.log(data); } catch (err) { console.log(err); } };

Koden är self-invoked function, dvs den kommer köras automatiskt vid load så du behöver inte anropa den.
Tror att felet eventuellt igger i din syntax för click eventet i din html.

Kan du skippa html och enbart köra scriptet för att se svar i console?

Permalänk
Skrivet av zaibuf:

Koden är self-invoked function, dvs den kommer köras automatiskt vid load så du behöver inte anropa den.
Tror att felet ligger i din syntax för click eventet i din html. Der är bättre att använda event listeners.

Kan du skippa html och enbart köra scriptet för att se svar i console?

ok, som document.ready eller vad det nu hette. Jag testade och det blev typ samma fel.

Hotell4.html:13 GET https://api.choice.no/energy/v1/health net::ERR_CONNECTION_RESET

Skrivet av KAD:

En GET-operation, där URL:en du anger är skyddad av Basic Authentication och där du låter bli att ange Authorization-headern ska ge HTTP Status 401 tillbaka:

HTTP/1.1 401 Unauthorized Date: Mon, 04 Feb 2014 16:50:53 GMT WWW-Authenticate: Basic realm="WallyWorld"

(exemplet taget från RFC 7617).

Nästan alla webbläsare skickar i det läget upp en liten ful dialogruta för att ange användarnamn och lösenord, i ditt fall det som benämns ClientId och ClientSecret. Det lättaste sättet att testa om API:et fungerar är alltså att klistra in URL:en i webbläsarens adressrad och trycka på enter. Gärna med webbläsarens debug-mode igång så att du kan se nätverkstrafiken. Det förväntade beteendet är alltså att du ska se ovanstående svar i debug-läget och att du ska få inloggningsdialogen i det ordinarie webbläsar-användargränssnittet. Med rätt användarnamn och lösenord angivet i dialogrutan ska resultatet komma tillbaka i webbläsarfönstret.

Samma sak går även att göra med curl eller liknande verktyg, vilket kanske är lättare att dokumentera när du hör av dig till supporten (eller skriver nya inlägg här).

Det låter på din felbeskrivning som om servern helt enkelt inte svarar - jag gissar alltså att webbläsaren inte ens lyckas skicka sin GET-request eller i alla fall inte får något vettigt svar. Om jag har rätt i att uppkopplingen inte lyckas kan det vara dags att börja misstänka brandväggar. I det läget plockar man fram Wireshark och kollar hur TCP-anslutningen beter sig, men det kräver grundläggande kunskap om TCP.

Några andra noteringar:
- Alla HTTP-headers har kolon efter sig, det har inte exemplet i ditt ursprungsinlägg
- En kommentar nämner OAUTH, men det är med stor sannolikhet en missuppfattning från din sida

OAUTH är fel från mig, någonstans på sidan som jag får min clientid och clientsecret från står det något om OAUTH 2.0, men samtidigt står det tydligt i exemplet att det är basic.

Wireshark har jag använt en del fast då kring mycket enkla protokoll.

Nå denna data fick jag ut här censurerad såklart

Source Protocol Info Client TCP *Serverport* → 443 [SYN] Seq=0 Win=**** Len=0 MSS=1460 WS=256 SACK_PERM=1 Server TCP 443 → *Serverport* [SYN, ACK] Seq=0 Ack=1 Win=******* Len=0 MSS=1460 SACK_PERM=1 Client TCP *Serverport* → 443 [ACK] Seq=1 Ack=1 Win=**** Len=0 Client TLSv1.2 Client Hello Server TLSv1.2 Server Hello, Change Cipher Spec Server TLSv1.2 Encrypted Handshake Message Client TCP *Serverport* → 443 [ACK] Seq=518 Ack=148 Win=******* Len=0 Client TLSv1.2 Change Cipher Spec, Encrypted Handshake Message Client TLSv1.2 Application Data Server TCP 443 → *Serverport* [ACK] Seq=148 Ack=569 Win=******* Len=0 Server TCP [TCP Dup ACK 72#1] 443 → *Serverport* [ACK] Seq=148 Ack=569 Win=******* Len=0 Server TCP 443 → *Serverport* [ACK] Seq=148 Ack=1060 Win=******* Len=0 Server TCP 443 → *Serverport* [RST, ACK] Seq=148 Ack=1060 Win=0 Len=0 Client TCP 25757 → 443 [SYN] Seq=0 Win=**** Len=0 MSS=1460 WS=256 SACK_PERM=1 Server TCP 443 →*ServerPort* [SYN, ACK] Seq=0 Ack=1 Win=******* Len=0 MSS=1460 SACK_PERM=1 Client TCP 25757 → 443 [ACK] Seq=1 Ack=1 Win=**** Len=0 Client TLSv1.2 Client Hello Server TCP 443 →*ServerPort* [ACK] Seq=1 Ack=518 Win=******* Len=0 Server TLSv1.2 Server Hello, Change Cipher Spec Server TLSv1.2 Encrypted Handshake Message Client TCP 25757 → 443 [ACK] Seq=518 Ack=148 Win=******* Len=0 Client TLSv1.2 Change Cipher Spec, Encrypted Handshake Message Client TLSv1.2 Application Data Server TCP 443 →*ServerPort* [ACK] Seq=148 Ack=569 Win=******* Len=0 Server TCP [TCP Dup ACK 11***#1] 443 →*ServerPort* [ACK] Seq=148 Ack=569 Win=******* Len=0 Server TCP 443 →*ServerPort* [ACK] Seq=148 Ack=1060 Win=******* Len=0 Server TCP 443 →*ServerPort* [RST, ACK] Seq=148 Ack=1060 Win=0 Len=0

Sista så säger servern en reset. När clienten sa Hello till servern, så borde servern vara mer artig och fråga mer och prata om vädret och annat.

Nå tackar för hjälpen. Även om jag ej lyckas så bidrar denna hjälp till att företaget jag kommer prata med inte ser mig för allt oinkompetent. Vi ska sälja in avancerade saker, men det är ej webbutveckling.

*edit*
Min tolning av wireshark. De pratar för fullt med varandra, servern gillar dock inte handskakningen.

*edit2*
Testade adressen direkt i webbläsaren, fick inget svar från den. Men wiresharp typ som innan.

Permalänk
Medlem
Skrivet av lillaankan_i_dammen:

ok, som document.ready eller vad det nu hette. Jag testade och det blev typ samma fel.

Hotell4.html:13 GET https://api.choice.no/energy/v1/health net::ERR_CONNECTION_RESET

OAUTH är fel från mig, någonstans på sidan som jag får min clientid och clientsecret från står det något om OAUTH 2.0, men samtidigt står det tydligt i exemplet att det är basic.

Wireshark har jag använt en del fast då kring mycket enkla protokoll.

Nå denna data fick jag ut här censurerad såklart

Source Protocol Info Client TCP *Serverport* → 443 [SYN] Seq=0 Win=**** Len=0 MSS=1460 WS=256 SACK_PERM=1 Server TCP 443 → *Serverport* [SYN, ACK] Seq=0 Ack=1 Win=******* Len=0 MSS=1460 SACK_PERM=1 Client TCP *Serverport* → 443 [ACK] Seq=1 Ack=1 Win=**** Len=0 Client TLSv1.2 Client Hello Server TLSv1.2 Server Hello, Change Cipher Spec Server TLSv1.2 Encrypted Handshake Message Client TCP *Serverport* → 443 [ACK] Seq=518 Ack=148 Win=******* Len=0 Client TLSv1.2 Change Cipher Spec, Encrypted Handshake Message Client TLSv1.2 Application Data Server TCP 443 → *Serverport* [ACK] Seq=148 Ack=569 Win=******* Len=0 Server TCP [TCP Dup ACK 72#1] 443 → *Serverport* [ACK] Seq=148 Ack=569 Win=******* Len=0 Server TCP 443 → *Serverport* [ACK] Seq=148 Ack=1060 Win=******* Len=0 Server TCP 443 → *Serverport* [RST, ACK] Seq=148 Ack=1060 Win=0 Len=0 Client TCP 25757 → 443 [SYN] Seq=0 Win=**** Len=0 MSS=1460 WS=256 SACK_PERM=1 Server TCP 443 →*ServerPort* [SYN, ACK] Seq=0 Ack=1 Win=******* Len=0 MSS=1460 SACK_PERM=1 Client TCP 25757 → 443 [ACK] Seq=1 Ack=1 Win=**** Len=0 Client TLSv1.2 Client Hello Server TCP 443 →*ServerPort* [ACK] Seq=1 Ack=518 Win=******* Len=0 Server TLSv1.2 Server Hello, Change Cipher Spec Server TLSv1.2 Encrypted Handshake Message Client TCP 25757 → 443 [ACK] Seq=518 Ack=148 Win=******* Len=0 Client TLSv1.2 Change Cipher Spec, Encrypted Handshake Message Client TLSv1.2 Application Data Server TCP 443 →*ServerPort* [ACK] Seq=148 Ack=569 Win=******* Len=0 Server TCP [TCP Dup ACK 11***#1] 443 →*ServerPort* [ACK] Seq=148 Ack=569 Win=******* Len=0 Server TCP 443 →*ServerPort* [ACK] Seq=148 Ack=1060 Win=******* Len=0 Server TCP 443 →*ServerPort* [RST, ACK] Seq=148 Ack=1060 Win=0 Len=0

Sista så säger servern en reset. När clienten sa Hello till servern, så borde servern vara mer artig och fråga mer och prata om vädret och annat.

Nå tackar för hjälpen. Även om jag ej lyckas så bidrar denna hjälp till att företaget jag kommer prata med inte ser mig för allt oinkompetent.

Känns som det snarare är nåt fel på servern för apiet än i ditt anrop det fallet.

Permalänk
Skrivet av zaibuf:

Känns som det snarare är nåt fel på servern för apiet än i ditt anrop det fallet.

ok, det är jag ute för rätt så ofta. Problemet är att när det är första gången man ska göra en sak så finns det stor risk att det felet är hos en. Nu har jag dock mer att gå för när jag ska argumentera.

Permalänk
Medlem

Eftersom du får en timeout, det är inte något så dumt som att de kräver TLS 1.2 och åtminstone med c# så får du inte det per default om du inte explicit sätter det.

ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;

Tex

Permalänk
Skrivet av Dhanjel:

Eftersom du får en timeout, det är inte något så dumt som att de kräver TLS 1.2 och åtminstone med c# så får du inte det per default om du inte explicit sätter det.

ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;

Tex

Tackar för hälpen. Problemet är dock löst. De hade ej låst upp API för mig och någon ändring...