Welcome to the SMS Hub

Please reference the documentation below in order to utilize the API.

Features/Highlights

Users Developers
  • Offers the ability to send texts using either Nexmo or Twilio
  • The rough cost for each system is $1/month per phone number purchased, and $7 per 1,000 texts sent. So, for about $19/year you could send 1000 text messages.
  • The system keeps a log of every message sent
  • The system supports STOP, UNSTOP, UNSUBSCRIBE or CANCEL requests, in accordance with industry standards.
  • The system supports pre-emptively opting out of text messages by program. Eg: Here's the link to opt-out of Ram Food Recovery texts
  • Ability for individual departments to view their own logs, via this site
  • Ability for individual departments to send text messages via API or this website
  • The system automatically sends opt-out information to any phone numbers texted for the first time.
  • The system can optionally prevent duplicate messages (ie, you can't send out the same message to the same user within a timeframe you specify)
  • Allows any web application (must be on-campus) to call an endpoint, via an API, in order to send a text message to any number capable of receiving texts
  • Provides a secured data transmission between calling application and the end application by using JSON web tokens. Here is the access point for requesting a token.
  • The current token expiry is once every 6 months; this is adjustable
  • Any calling application using this endpoint must be located on-campus, as my tool is published to the WSNETDEV server (which is firewalled)
  • The system has the ability to send debugging e-mails instead of text messages
  • When using Twilio, the system automatically provides the following features:
    • Scaler distributes your outbound messaging traffic evenly across the phone numbers in your Messaging Service to help you handle higher messaging volume.
    • Sticky sender: ensures the same From phone number is selected every time your application messages a particular recipient (assuming you have purchased two or more numbers).
    • Long incoming messages that carriers break up and send to your app are automatically reassembled in order so content isn't jumbled.
    • More features as described at https://www.twilio.com/docs/sms/services

Limitations

  • Both Nexmo and Twilio impose rate limiting of 1 SMS per second. This SMS hub automatically throttles messages for you (in the case of Nexmo), or if you use Twilio, this is done automatically for you (if you create a messaging service - see below)
  • In the Billing and Payments section of either site, please be sure to enable Auto reload so that you don't risk running out of credits!!

Getting Started - Workflow/Implementation Details

Twilio Nexmo
  1. First sign up for a new Twilio account at https://www.twilio.com/docs/usage/tutorials/how-to-use-your-free-trial-account in order to get an API key pair. There is a small cost to use this long-term (they will give you $15 worth of few free credits). It is around $7 per 1000 text messages sent (Twilio and Nexmo cost roughly the same, although using Nexmo will incur a foreign transaction fee, as it is based overseas).
  2. Make sure you purchase at least one phone number via the site, preferably one that looks local (eg, Twilio has a large # of 970 numbers)
  3. It is strongly advised that you enable/create a new messaging service (also called CoPilot): Here are some reasons why you should consider CoPilot
  4. Make sure you configure auto-recharge
  5. Next send the Nexmo keys, your rented number, and program name to Shaun; he will create a new program identifier and private key for you within the SMS Hub database. So, you will now have 4 keys, all of which are stored in the database.
  6. Once you are given program identifier and key from Shaun, you can now begin using the "SMS Hub" to fire off text messages, one at a time. You will need the following pieces of information to do so:
    1. To Login (used only once, to generate an authorization token):
      1. ProgramSID (ie, your user name)
      2. ProgramKey (ie, your password)
    2. To Send a Text (which requires a token):
      1. Token (passed as a part the header)
      2. Message
      3. PhoneNumber
  1. First sign up for a new Nexmo account at https://www.nexmo.com/ in order to get an API key pair. There is a small cost to use this long-term (they will give you $2 worth of few free credits). It is around $7 per 1000 text messages sent, which is slightly cheaper than Twilio. If you wish to use Twilio, the process is the same (support for Twilio should be finished soon).
  2. Next visit https://dashboard.nexmo.com, log in with your account credentials, and then select Numbers --> Buy Numbers to identify and select a number for your program (any number works and many 970 numbers are available in the system, but be sure to select Mobile and NOT landline or toll-free numbers). Also, rented numbers can be swapped out at any time (so you're not stuck with whatever number you choose). A final recommendation is to visit the "Billing and payments" section of the site and enable auto-reload in order to be sure you never run out of credits. Alternatively, you can go to Settings --> Account Settings and enable balance alerts if you would rather renew manually (and not store your credit card number on Nexmo's site).
  3. Next send the Nexmo keys, your rented number, and program name to Shaun; he will create a new program identifier and private key for you within the SMS Hub database. So, you will now have 4 keys, all of which are stored in the database.
  4. Once you are given program identifier and key from Shaun, you can now begin using the "SMS Hub" to fire off text messages, one at a time. You will need the following pieces of information to do so:
    1. To Login (used only once, to generate an authorization token):
      1. ProgramSID (ie, your user name)
      2. ProgramKey (ie, your password)
    2. To Send a Text (which requires a token):
      1. Token (passed as a part the header)
      2. Message
      3. PhoneNumber

Getting a Token


You can use a REST client tool (I use Restlet) to make a post to call the endpoint visually (click for larger image):

login

Input for above screen capture:

            {
                "ProgramSID": "xxx",
                "ProgramKey": "yyy"
            }

Here is some sample C# code to generate a JSON web token used for authentication:

try

{

//create a new http client to get a token using (var client = new HttpClient())

{

// perform a json post

client.BaseAddress = new Uri(Request.Url.AbsoluteUri); client.DefaultRequestHeaders.Accept.Clear(); client.DefaultRequestHeaders.Accept.Add(new

MediaTypeWithQualityHeaderValue("application/json"));

//instantiate a new officeProgram instance OfficeProgram officeProgram = new OfficeProgram

{

ProgramSID = "123",

ProgramKey = "123"

};

//post async, await response

HttpResponseMessage response = await

client.PostAsJsonAsync("api/Login", officeProgram); response.EnsureSuccessStatusCode();

if (response.IsSuccessStatusCode)

{

token = response.Content.ReadAsStringAsync().Result;

// replace "\" from resulting string

token = token.Replace(@"\", string.Empty).Replace("\"", "");

}

}

}

catch (Exception e)

{

Console.WriteLine(e.Message); return RedirectToAction("Error");

}

if (string.IsNullOrEmpty(token))

throw new HttpException(401, "You are unauthorized");

Using jQuery:

<script type="text/javascript">
                $(function () {
                var dataJSON = { ProgramSID: "123", ProgramKey: "123" };
                    $.ajax({
                        type: 'POST',
                        url: '/api/Login',
                        data: JSON.stringify(dataJSON),
                        contentType: 'application/json; charset=utf-8',
                        dataType: 'json',
                        success: function (token, textStatus, jQxhr) {
                            console.log('token: ' + token);
                            SendText(token);
                        },
                        error: function (jqXhr, textStatus, errorThrown) {
                            console.log(errorThrown);
                        }
                    });
                });
 
                </script>
            

PHP:

<?php
function sms_demo() {
                /*************************
		    BASE VARS
	*************************/
                $phone = '19705551234';
                $programId = 'd2b67be0-79a2-49dd-9476-7c793fdc3297';
                $programIdentifier = '123';
                $programKey = '123';
                $api_url = 'https://wsnetdev2.colostate.edu/cwis463/api';
                $auth_tkn = '';
                /*************************
		  AUTHORIZATION
	*************************/
                // Build post
                $auth_url = $api_url . '/Login';
                $auth_body = array(
                'ProgramSID' => $programIdentifier,
                'ProgramKey' => $programKey
		);
                // Send post and get response
                $auth_response = wp_remote_post( $auth_url, array(
                'method' => 'POST',
                'body' => $auth_body
		)
	);
                // Set auth token (and strip wrapping quotes)
                $auth_tkn = trim($auth_response['body'], '"');
?>

Sending a Text

The JWT token response is what is used to then be able to access the secured endpoint in the hub (the function to send an SMS).

send

Input for above screen capture:

                {
                "Message": "hey there",
                "PhoneNumber": "19706904544"
                }

Here's an example using C#:

// if we made it this far, we have a token for an actual test to post a text

message

try

{

//create another new http client using (var client = new HttpClient())

{

// perform a json post

client.BaseAddress = new Uri(Request.Url.AbsoluteUri); client.DefaultRequestHeaders.Accept.Clear(); client.DefaultRequestHeaders.Accept.Add(new

MediaTypeWithQualityHeaderValue("application/json"));

//if you just want to test passing along a token without logging in, uncomment 2 lines below and comment out line 89

//string manuallyCreatedToken = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1bmlxdWVfbmFtZSI6IjZ5bVhVVFBmeU5HNnBCamQiLCJuYmYi OjE1NDA1NzQ5MTgsImV4cCI6MTU1NjI5OTcxOCwiaWF0IjoxNTQwNTc0OTE4LCJpc3MiOiJodHRwOi8vbG9jYWxob 3N0OjUwMTkxIiwiYXVkIjoiaHR0cDovL2xvY2FsaG9zdDo1MDE5MSJ9.PRpEJKAsAUeyqp8l5rqgxWPmnKT2x098e Njxu2X2Xtw";

//client.DefaultRequestHeaders.Add("Authorization",

manuallyCreatedToken); client.DefaultRequestHeaders.Add("Authorization", token);

//Instantiate a new text message instance TextMessage textMessage = new TextMessage

{

ProgramId = new Guid("d2b67be0-79a2-49dd-9476-7c793fdc3297"), Message = DateTime.Now.ToString(),

PhoneNumber = "19706904544"

};

//post async, await response

HttpResponseMessage response = await client.PostAsJsonAsync("api/TextMessages", textMessage);

Here's an example using jQuery:

function SendText(token) {
                        $(function () {
                var dataJSON = { ProgramId: "D2B67BE0-79A2-49DD-9476-7C793FDC3297", Message: "my message", PhoneNumber: "19706904544" };
                            $.ajax({
                                beforeSend: function (xhr) {
                                    xhr.setRequestHeader('Authorization', + token);
                                },
                                type: 'POST',
                                url: '/api/TextMessages',
                                data: JSON.stringify(dataJSON),
                                contentType: 'application/json; charset=utf-8',
                                dataType: 'json',
                                success: function (token, textStatus, jQxhr) {
                                    console.log("Message sent!");
                                },
                                error: function (jqXhr, textStatus, errorThrown) {
                                    console.log(errorThrown);
                                }
                            });
                        });
                    }
            

PHP:

<?php
                /*************************
                		    SEND TEXT
                	*************************/
                // Build post
                $sms_url = $api_url . '/TextMessages';
                $sms_headers = array(
                'Content-type' => 'application/json',
                'Authorization' => $auth_tkn
            );
                $sms_body = array(
                'ProgramId' => $programId,
                'PhoneNumber' => $phone,
                'Message' => 'This is a text from demo.',
                'DateSent' => current_time('mysql')
            );
                // Send post
                $sms_response = wp_remote_post( $sms_url, array(
                'method' => 'POST',
                'data-format' => 'body',
                'headers' => $sms_headers,
                'body' => json_encode($sms_body)
            )
            );
            }
                ?>
            

More Code Samples - C#

using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Net.Mail;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using System.Web;


namespace QualtricsAPIDemo.Models
{


                    public class DSATextMessages
    {
                    private static string baseuri = "https://wsnetdev2.colostate.edu/cwis463/";
                    private static string authuri = "api/Login";
                    private static string posturi = "api/TextMessages";
                    private static string programidentifier = "xxx";
                    private static string programkey = "yyy";
                    private string token = ""; // this changes periodically, it will email the support address when it changes
                    private static string supportaddress = "stuach_web_team@mail.colostate.edu";
                    private static string fromaddress = "stuach_web_team@mail.colostate.edu";
                    private static string smtpserver = "smtp.colostate.edu";
                    private static string smtpport = "25"; //587;  
                    private static string smtpusername = "";
                    private static string smtppassword = "";//no auth credentials required for us,
                    private HttpClient client;




                    public DSATextMessages()
        {
            client = new HttpClient();
            client.BaseAddress = new Uri(baseuri);
            ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
                    //client.DefaultRequestHeaders.Accept.Clear();
                    //client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
                    // If you have no basic authentication, you can skip thses lines
                    //var authToken = Encoding.ASCII.GetBytes($"{authUserName}:{authPassword}");
                    //client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Basic", Convert.ToBase64String(authToken));

                    // if you just want to test passing along a token without logging in, uncomment 2 lines below and comment out line xx
                    //string manuallyCreatedToken = "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1bmlxdWVfbmFtZSI6IjZ5bVhVVFBmeU5HNnBCamQiLCJuYmYi OjE1NDA1NzQ5MTgsImV4cCI6MTU1NjI5OTcxOCwiaWF0IjoxNTQwNTc0OTE4LCJpc3MiOiJodHRwOi8vbG9jYWxob 3N0OjUwMTkxIiwiYXVkIjoiaHR0cDovL2xvY2FsaG9zdDo1MDE5MSJ9.PRpEJKAsAUeyqp8l5rqgxWPmnKT2x098e Njxu2X2Xtw";
                    //client.DefaultRequestHeaders.Add("Authorization", manuallyCreatedToken);

                    //authorization headers are also added after doing the Authorization call.
        }

        ~DSATextMessages()
        {
            client.Dispose();
        }

                    /// <summary>
                    /// Authenticate only needs to be called occasionally when a new token is needed.
                    /// </summary>
                    /// <returns>true for success, but throws an error on failure</returns>
                    private bool Authenticate()
        {

                    // create a new http client to get a token 
                    /*
             * POST: https://wsnetdev2.colostate.edu/cwis463/api/Login 
             BODY:
                {
                "ProgramSID": "6ymXUTPfyNG6pBjd", "ProgramKey": "vUfprLLcKJ6MFBFuCntvLCsHB53xusCp"
                }
*/

                    string authrequest = @"{""ProgramSID"": ""{pi}"", ""ProgramKey"": ""{pk}""}".Replace("{pi}", programidentifier).Replace("{pk}", programkey);

                    // The actual put method including error handling
                    using (
                    //var content = new StringContent(postData)
                    var content = new StringContent(authrequest, System.Text.Encoding.UTF8, "application/json")
            )
            {
                    try
                {
                    client.DefaultRequestHeaders.Remove("Authorization");
                }
                    catch { /* not there?  that's ok.  */ }
                HttpResponseMessage response = null;
                    //await client.PostAsync(authuri, content);
                Task.Factory.StartNew(() => {
                    //Make async web request
                    response = client.PostAsync(authuri, content).Result;
                });

                    int count_tries = 0;
                    while (response == null && count_tries < 60) // delay for up to a minute -> this allows the threading to pop back and forth between tasks
                {
                    count_tries++;
                    Thread.Sleep(1000);
                }

                    if (response == null)
                {
                    throw new Exception("Authentication attempt timed out during request");
                }

                    if (response.IsSuccessStatusCode)
                {

                    string newtoken = null;
                    Task.Factory.StartNew(() => {
                    //Make async web request
                        newtoken = response.Content.ReadAsStringAsync().Result;
                    });

                    count_tries = 0;
                    while (newtoken == null && count_tries < 60) // delay for up to a 20 seconds -> this allows the threading to pop back and forth between tasks
                    {
                        count_tries++;
                        Thread.Sleep(200);
                    }

                    if (newtoken == null)
                    {
                    throw new Exception("Authentication attempt timed out during response read");
                    }
                    token = newtoken;
                    token = token.Replace(@"\", string.Empty).Replace("\"", "");
                    EmailWebTeam("New TM Token", token);

                    try
                    {
                        client.DefaultRequestHeaders.Remove("Authorization");
                    }
                    catch { /* not there?  that's ok.  just add them */ }
                    client.DefaultRequestHeaders.Add("Authorization", "Bearer " + token);

                    return true;
                }
                    else
                {

                    throw new Exception("Authorization failed " + response.StatusCode.ToString() + " " + response.ReasonPhrase);
                    //return false;
                }
            }

        }



                    /// <summary>
                    /// This one can be run asynchronously if you don't care about the result
                    /// </summary>
                    /// <param name="textMessage">This variable is updated with success and result</param>
                    /// <returns></returns>
                    public async Task<TextMessage> SendText(TextMessage textMessage)
        {
                    /*
             * POST: https://wsnetdev2.colostate.edu/cwis463/api/TextMessages 
             HEADERS: Authorization

            Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1bmlxdWVfbmFtZSI6IjZ5bVhVVFBmeU5HNnBCamQiLCJuYmYi OjE1NDA1NzQ5MTgsImV4cCI6MTU1NjI5OTcxOCwiaWF0IjoxNTQwNTc0OTE4LCJpc3MiOiJodHRwOi8vbG 9jYWxob3N0OjUwMTkxIiwiYXVkIjoiaHR0cDovL2xvY2FsaG9zdDo1MDE5MSJ9.PRpEJKAsAUeyqp8l5rqgxW PmnKT2x098eNjxu2X2Xtw

            BODY:

            {
            "Message": "Hello world!",
            "PhoneNumber": "19706904544"
            }

*/
            TextMessage resultingTM = new TextMessage();
            resultingTM.PhoneNumber = textMessage.PhoneNumber;
            resultingTM.Message = textMessage.Message;

                    using (
                    //var content = new StringContent(postData)
                    var content = new StringContent(JsonConvert.SerializeObject(textMessage), System.Text.Encoding.UTF8, "application/json")
            )
            {
                    try
                {
                    client.DefaultRequestHeaders.Remove("Authorization");
                }
                    catch { /* not there?  that's ok.  just add them */ }
                client.DefaultRequestHeaders.Add("Authorization", "Bearer " + token);

                    // post async, await response 
                HttpResponseMessage response = await client.PostAsync(posturi, content);

                    if (response.IsSuccessStatusCode)
                {
                    resultingTM.SentResult = await response.Content.ReadAsStringAsync();
                    resultingTM.SendSuccessful = true;
                }
                    else
                {
                    resultingTM.SentResult = "Error: " + response.StatusCode + " " + response.ReasonPhrase + ". " + response.Content.ReadAsStringAsync().Result;
                    resultingTM.SendSuccessful = false;

                    if (response.StatusCode == HttpStatusCode.Unauthorized)
                    {
                    // token timed out?  Try authenticating and doing this again.
                        Authenticate();

                    using (
                    //var content = new StringContent(postData)
                    var contentAgain = new StringContent(JsonConvert.SerializeObject(textMessage), System.Text.Encoding.UTF8, "application/json")
                        )
                        {
                            response = await client.PostAsync(posturi, contentAgain);

                    if (response.IsSuccessStatusCode)
                            {
                                resultingTM.SentResult = await response.Content.ReadAsStringAsync();
                                resultingTM.SendSuccessful = true;
                            }
                    else
                            {
                                resultingTM.SentResult = "Error: " + response.StatusCode + " " + response.ReasonPhrase + ". " + response.Content.ReadAsStringAsync().Result;
                                resultingTM.SendSuccessful = false;
                            }
                        }

                    }
                }
            } // end of content

                    return resultingTM;

        } // end of Send Text



                    public static TextMessage SendTextAndWaitForResponse(string phonenumber, string message)
        {
            TextMessage textmessage = new TextMessage();
            textmessage.PhoneNumber = phonenumber;
            textmessage.Message = message;

                    return SendTextAndWaitForResponse(textmessage);
        }

                    public static TextMessage SendTextAndWaitForResponse(TextMessage textMessage)
        {
            DSATextMessages tm = new DSATextMessages();
            TextMessage resultingTM = null;


                    if (!IsPhoneNumber(textMessage.PhoneNumber))
            {
                resultingTM = new TextMessage();
                resultingTM.PhoneNumber = textMessage.PhoneNumber;
                resultingTM.Message = textMessage.Message;
                resultingTM.SendSuccessful = false;
                resultingTM.SentResult = "Invalid phone number " + textMessage.PhoneNumber;
                    return resultingTM;
            }

                    //Task.Factory.StartNew(() =>  // this syntax uses a thread from the pool, less overhead
                    //new Thread(() =>  // this syntax creates a separate thread than the pool, more overhead, but pool is preserved
            Task.Factory.StartNew(() => {
                    //Make async web request
                    try
                {
                    resultingTM = tm.SendText(textMessage).Result;
                }
                    catch (Exception ex)
                {
                    resultingTM = new TextMessage();
                    resultingTM.PhoneNumber = textMessage.PhoneNumber;
                    resultingTM.Message = textMessage.Message;
                    resultingTM.SendSuccessful = false;
                    resultingTM.SentResult = ex.InnerException.Message;
                }
            });

                    int count_tries = 0;
                    while (resultingTM == null && count_tries < 60) // delay for up to a minute -> this allows the threading to pop back and forth between tasks
            {
                count_tries++;
                Thread.Sleep(1000);
            }

                    if (resultingTM == null)
            {
                resultingTM = new TextMessage();
                resultingTM.PhoneNumber = textMessage.PhoneNumber;
                resultingTM.Message = textMessage.Message;
                resultingTM.SendSuccessful = false;
                resultingTM.SentResult = "Timeout sending message";
            }

                    return resultingTM;
        }

                    public static TextMessage SendTextToMultipleAndWaitForResponse(List<string> phonenumberlist, string message)
        {
            TextMessage textmessage = new TextMessage();
            textmessage.PhoneNumber = String.Join(",", phonenumberlist);
            textmessage.Message = message;

                    return SendTextToMultipleAndWaitForResponse(textmessage);
        }

                    public static TextMessage SendTextToMultipleAndWaitForResponse(string phonenumberlist, string message)
        {
            TextMessage textmessage = new TextMessage();
            textmessage.PhoneNumber = phonenumberlist;
            textmessage.Message = message;

                    return SendTextToMultipleAndWaitForResponse(textmessage);
        }

                    /// <summary>
                    /// textMessage.PhoneNumber can have multiple comma delimited phone numbers
                    /// </summary>
                    /// <param name="textMessage"></param>
                    /// <returns></returns>
                    public static TextMessage SendTextToMultipleAndWaitForResponse(TextMessage textMessage)
        {

            DSATextMessages tm = new DSATextMessages();
            TextMessage resultingTM = null;

                    //Task.Factory.StartNew(() =>  // this syntax uses a thread from the pool, less overhead
                    //new Thread(() =>  // this syntax creates a separate thread than the pool, more overhead, but pool is preserved
            Task.Factory.StartNew(() => {
                    //Make async web request
                    try
                {
                    resultingTM = tm.SendText(textMessage).Result;
                }
                    catch (Exception ex)
                {
                    resultingTM = new TextMessage();
                    resultingTM.PhoneNumber = textMessage.PhoneNumber;
                    resultingTM.Message = textMessage.Message;
                    resultingTM.SendSuccessful = false;
                    resultingTM.SentResult = ex.InnerException.Message;
                }
            });

                    int count_tries = 0;
                    while (resultingTM == null && count_tries < 60) // delay for up to a minute -> this allows the threading to pop back and forth between tasks
            {
                count_tries++;
                Thread.Sleep(1000);
            }

                    if (resultingTM == null)
            {
                resultingTM = new TextMessage();
                resultingTM.PhoneNumber = textMessage.PhoneNumber;
                resultingTM.Message = textMessage.Message;
                resultingTM.SendSuccessful = false;
                resultingTM.SentResult = "Timeout sending message";
            }

                    return resultingTM;
        }

                    public static bool IsPhoneNumber(string number)
        {
                    long po = 0;
                    return long.TryParse(number, out po);
                    //return Regex.Match(number, @"^(\+[0-9]{9})$").Success;
        }

                    public static void EmailWebTeam(string subject, string message)
        {
            Task.Factory.StartNew(() =>
            {
                    var body = "<p>{0}</p>";
                MailMessage email = new MailMessage();
                email.To.Add(new MailAddress(supportaddress));
                email.From = new MailAddress(fromaddress);
                email.Subject = subject;
                email.Body = string.Format(body, message);
                email.IsBodyHtml = true;

                    using (var smtp = new SmtpClient())
                {
                    if (smtpusername != null && smtpusername != "")
                    {
                    var credential = new NetworkCredential
                        {
                            UserName = smtpusername,
                            Password = smtppassword
                        };
                        smtp.Credentials = credential;
                    }
                    smtp.Host = smtpserver;
                    smtp.Port = Convert.ToInt32(smtpport);
                    smtp.EnableSsl = true;
                    smtp.Send(email);

                }

            });
            Thread.Sleep(10);
        }


                    public class TextMessage
        {
                    //public Guid ProgramId { get { return programguid; } set { throw new Exception("cannot set GUID"); } }
                    public string Message { get; set; }
                    private string _PhoneNumber = "";
                    public string PhoneNumber { get { return _PhoneNumber; } set { _PhoneNumber = value.Replace(" ", "").Replace("(", "").Replace(")", "").Replace("-", "").Replace(".", "").Replace("+", ""); } }
                    public bool? SendSuccessful { get; set; }
                    public string SentResult { get; set; }
        }
    }
}

    

What is JWT?

  1. What is JWT?
    • Can securely transfer info between any two points; eg, an API
    • Work across any programming language
    • They are self-contained
    • It is compact, you can send via a post request as a header and can be passed around easily
    • Fast transmission
    • Avoids querying the db multiple times – the token is all that is required.
  2. A JWT consists of a header, payload, and a signature in the format of aaaaa.bbbbbb.cccccc
    • eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
      • 2 parts, the type (JWT), and the hashing algorithm (HMAC)
    • eyJ1bmlxdWVfbmFtZSI6IjZ5bVhVVFBmeU5HNnBCamQiLCJuYmYiOjE1NDA1NzQ5MTgsImV4cCI6MTU1NjI5OTcxOCwiaWF0IjoxNTQwNTc0OTE4LCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjUwMTkxIiwiYXVkIjoiaHR0cDovL2xvY2FsaG9zdDo1MDE5MSJ9
      • The claim or info you want to submit, such as user details
    • PRpEJKAsAUeyqp8l5rqgxWPmnKT2x098eNjxu2X2Xtw
      • The signature is made up of a hash of the header, the payload, and the secret

More information can be found at https://scotch.io/tutorials/the-anatomy-of-a-json-web-token