Welcome to the Panopto Community

Please note: All new registrants to the Panopto Community Forum must be approved by a forum moderator or admin. As such, if you navigate to a feature that is members-only, you may receive an error page if your registration has not yet been approved. We apologize for any inconvenience and are approving new members as quickly as possible.

Rest API Authentication Issue..

edited May 2021 in API

Hi there. I'm using the Rest API & trying to authenticate a user. using C#. I'm getting the following error:

StatusCode: 400, ReasonPhrase: 'Bad Request'


I'm following the documentation : (I cannot insert the link due to my account being new) however it's entitled

Getting an access token

2.1. Getting a token for a User Based Server Application (Fig. 1). 

I will omit the variable content due to privacy..

The clientId & clientSecret are exactly as was displayed in the API Clients Page & they are of the type "User Based Server Application".

Just want to confirm that I'm using the correct parameters & url paths where they expected.

 

var  userPassword = clientId.ToLower() + ":" + clientSecret.ToLower();

userPassword = Convert.ToBase64String(Encoding.ASCII.GetBytes(userPassword));

var appKey = ***application key under System -> Identity Providers ***

var userKey = *** lowercase username ***

var password = Convert.ToBase64String(sha256(userKey.ToLower() + "|" + appKey.ToLower()));


HttpClientHandler handler = new HttpClientHandler();

HttpClient client = new HttpClient(handler);

client.BaseAddress = new Uri(baseUrl);

client.DefaultRequestHeaders.Accept.Clear();

client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", userPassword);

HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, "/Panopto/oauth2/connect/token");

request.Headers.Add("Grant_type", "password");

request.Headers.Add("Username", userKey.ToLower());

 request.Headers.Add("Password", password);

 request.Headers.Add("scope", "api");



Thanks in advance!

Answers

  • @paul redmond I responded to a similar question: https://community.panopto.com/discussion/1180/retrieve-folder-id-by-searching-on-folder-name

    Your case looks like the Username isn't scoped instancename\USERNAME. You might also have the "sha256 is not used for internal users" issue too, I can't tell for sure. I hope this helps! 😁

  • Thanks for your reply Jonathan. I've tried multiple times & am still getting the "Bad Response", 400 error.

    I added the instance name ie. panoptointernal\USERNAME & removed the sha256.

    Considering this is an Api Client -> User Based Server Application I'm assuming the USERNAME is the "Client Name" within the Api Client settings?

    Just to confirm when you mention PASSWORD, I've tried using the client secret here & also tried populating it with the Base64String (clientId.ToLower() + ":" + clientSecret.ToLower()).

  • Kevin BaumKevin Baum Panopto Employee

    Hi Paul,

    In looking at the sample you provided, it looks like you are adding the grant_type, username, password, and scope to the headers of the request. Is that correct?

    If so, those parameters should instead be moved to be form parameters on the request, and not in the headers. That would explain why you are getting an HTTP 400 response.

    On the user name, is the user an internal Panopto user, or is the user coming from an external ID Provider? If they are internal, then you shouldn't need to add the application key, or hash the password using SHA-256. For internal users, you should just need to send their user key (without the instance name) and password in their respective fields for the POST request.

    I hope this helps, please let me know if you have any other questions.

    Thanks,

    Kevin

  • edited May 2021

    Hi Kevin. Thanks for your response. I was trying a user with SSO however I have since created an internal user for simplicity sake..

    This is what I'm currently working with & still getting the 400 bad request.


    userPassword = clientId.ToLower() + ":" + clientSecret.ToLower();

    userPassword = Convert.ToBase64String(Encoding.ASCII.GetBytes(userPassword));

    HttpClient client = new HttpClient();

    client.BaseAddress = new Uri(baseUrl);

    var req = new HttpRequestMessage(HttpMethod.Post, "/Panopto/oauth2/connect/token");

    req.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

    req.Headers.Authorization = new AuthenticationHeaderValue("Basic", userPassword);

    req.Content = new FormUrlEncodedContent(new Dictionary<string, string>

    {

              {"Grant_type", "password" },

              {"Username", internalUserKey },     

    // -> INSTANCENAME\\USERNAME which looks like this -> panoptointernal\\USERNAME

    // also tried panoptointernal\USERNAME with a single slash

              {"Password", internalUserPassword },  // -> internal Users password

              {"Scope", "api" }

    });

  • Just an FYI so nobody wastes time looking at this I resolved it earlier today and I'll update tomorrow with findings after I test a couple of things. Cheers

  • edited May 2021

    The issue I was having was I was lowercasing my clientId & secret. What I did find out though was that instead of passing the authorization header "Basic " + auth_key is that you can just add the parameters "client_id" & "client_secret" in the body of the request with the others & that will validate also.

    Another thing is the USERNAME does not need the instancename\USERNAME it can just be USERNAME.


    Thanks for all who chimed in..

  • Hi @paul redmond

    Would you be able to share the working code here in case anyone else runs into a similar issue?

  • edited May 2021

    Sure thing Jonathon.


    authKey = clientId + ":" + clientSecret;

            authKey = Convert.ToBase64String(Encoding.ASCII.GetBytes(userPassword));

       HttpClient client = new HttpClient();

       client.BaseAddress = new Uri(baseUrl);

           HttpRequestMessage tokenRequest = new HttpRequestMessage(HttpMethod.Post, "/Panopto/oauth2/connect/token");

             tokenRequest.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

             tokenRequest.Headers.Authorization = new AuthenticationHeaderValue("Basic", authKey );

             HttpContent httpContent = new FormUrlEncodedContent(

              new[]

              {

              new KeyValuePair<string, string>("grant_type", "password"),

              new KeyValuePair<string, string>("username", internalUserKey),

              new KeyValuePair<string, string>("password", internalUserPassword),

              new KeyValuePair<string, string>("scope", "api")

              });

            tokenRequest.Content = httpContent;

            tokenRequest.Content.Headers.ContentType = new MediaTypeHeaderValue("application/x-www-form-urlencoded");


            var response = Task.Run(async () => await client.SendAsync(tokenRequest));


            Task<string> values = response.Result.Content.ReadAsStringAsync();

            var retToken = values.Result;

  • edited May 2021

    Sure thing Jonathon.


    authKey = clientId + ":" + clientSecret;

    authKey = Convert.ToBase64String(Encoding.ASCII.GetBytes(authKey));

    HttpClient client = new HttpClient();

    client.BaseAddress = new Uri(baseUrl);

    HttpRequestMessage tokenRequest = new HttpRequestMessage(HttpMethod.Post, "/Panopto/oauth2/connect/token");

    tokenRequest.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

    tokenRequest.Headers.Authorization = new AuthenticationHeaderValue("Basic", authKey );

    HttpContent httpContent = new FormUrlEncodedContent(

     new[]

     {

     new KeyValuePair<string, string>("grant_type", "password"),

     new KeyValuePair<string, string>("username", internalUserKey),

     new KeyValuePair<string, string>("password", internalUserPassword),

     new KeyValuePair<string, string>("scope", "api")


     });

    tokenRequest.Content = httpContent;

    tokenRequest.Content.Headers.ContentType = new MediaTypeHeaderValue("application/x-www-form-urlencoded");

    var response = Task.Run(async () => await client.SendAsync(tokenRequest));

    Task<string> values = response.Result.Content.ReadAsStringAsync();

    var retToken = values.Result;

  • That all makes sense to me and looks like what I would expect. They might be a small typo on the second line? I would expect it to be authKey that gets converted to base64 instead of the previously undefined userPassword. Something like:

    authKey = Convert.ToBase64String(Encoding.ASCII.GetBytes(authKey));
    
  • you're correct.. I changed the variable name as I was pasting it to make more sense to the reader. -- will update it.

    Thanks

Sign In or Register to comment.