Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/CODEOWNERS
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
# Global rule:
* @Bandwidth-Samples/dx
* @Bandwidth-Samples/band-swi @Bandwidth-Samples/band-devx
19 changes: 19 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
version: 2

updates:
- package-ecosystem: nuget
directory: /
schedule:
interval: monthly
open-pull-requests-limit: 5
ignore:
- dependency-name: "Bandwidth.Sdk"
update-types:
- version-update:semver-minor
- version-update:semver-patch
groups:
dependencies:
patterns:
- "*"
exclude-patterns:
- "Bandwidth.Sdk"
15 changes: 15 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
name: Test

on:
pull_request:
branches:
- main
schedule:
- cron: "0 9 * * 1"

jobs:
contract-test:
name: Contract Test
uses: Bandwidth-Samples/sample-app-tooling/.github/workflows/csharp.yml@main
with:
sample: mfa-cli
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (c) 2022 Bandwidth Samples
Copyright (c) 2026 Bandwidth Samples

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
182 changes: 106 additions & 76 deletions Program.cs
Original file line number Diff line number Diff line change
@@ -1,76 +1,106 @@
using Bandwidth.Standard.Api;
using Bandwidth.Standard.Client;
using Bandwidth.Standard.Model;

string BW_USERNAME;
string BW_PASSWORD;
string BW_MESSAGING_APPLICATION_ID;
string BW_ACCOUNT_ID;
string BW_VOICE_APPLICATION_ID;
string BW_NUMBER;

//Setting up environment variables
try
{
BW_USERNAME = Environment.GetEnvironmentVariable("BW_USERNAME");
BW_PASSWORD = Environment.GetEnvironmentVariable("BW_PASSWORD");
BW_MESSAGING_APPLICATION_ID = Environment.GetEnvironmentVariable("BW_MESSAGING_APPLICATION_ID");
BW_ACCOUNT_ID = Environment.GetEnvironmentVariable("BW_ACCOUNT_ID");
BW_VOICE_APPLICATION_ID = System.Environment.GetEnvironmentVariable("BW_VOICE_APPLICATION_ID");
BW_NUMBER = System.Environment.GetEnvironmentVariable("BW_NUMBER");
}
catch (Exception)
{
Console.WriteLine("Please set the environmental variables defined in the README");
throw;
}


Configuration configuration = new Configuration();
configuration.Username = BW_USERNAME;
configuration.Password = BW_PASSWORD;

MFAApi mfaApiInstance = new MFAApi(configuration);

Console.WriteLine("Enter phone number in E164 format (+15554443333): ");
string phoneNumber = Console.ReadLine();

Console.WriteLine("Enter MFA request method (voice/messaging). Default is messaging:");
string method = Console.ReadLine().ToLower();

CodeRequest codeRequest = new CodeRequest(
to: phoneNumber,
from: BW_NUMBER,
applicationId: method == "voice" ? BW_VOICE_APPLICATION_ID : BW_MESSAGING_APPLICATION_ID,
scope: "scope",
digits: 6,
message: "Your temporary {NAME} {SCOPE} code is {CODE}"
);

if (method == "voice")
{
mfaApiInstance.GenerateVoiceCode(BW_ACCOUNT_ID, codeRequest);
}
else
{
mfaApiInstance.GenerateMessagingCode(BW_ACCOUNT_ID, codeRequest);
}

Console.WriteLine("Enter the code you received: ");
string code = Console.ReadLine();

VerifyCodeRequest verifyCodeRequest = new VerifyCodeRequest(
to: phoneNumber,
scope: "scope",
expirationTimeInMinutes: 3,
code: code
);

if (mfaApiInstance.VerifyCode(BW_ACCOUNT_ID, verifyCodeRequest).Valid)
{
Console.WriteLine("Code is valid");
}
else
{
Console.WriteLine("Code is invalid");
}
using System.Text.RegularExpressions;
using Bandwidth.Standard.Api;
using Bandwidth.Standard.Client;
using Bandwidth.Standard.Model;

//Setting up environment variables
string? BW_ACCOUNT_ID = Environment.GetEnvironmentVariable("BW_ACCOUNT_ID");
string? BW_CLIENT_ID = Environment.GetEnvironmentVariable("BW_CLIENT_ID");
string? BW_CLIENT_SECRET = Environment.GetEnvironmentVariable("BW_CLIENT_SECRET");
string? BW_NUMBER = Environment.GetEnvironmentVariable("BW_NUMBER");
string? BW_VOICE_APPLICATION_ID = Environment.GetEnvironmentVariable("BW_VOICE_APPLICATION_ID");
string? BW_MESSAGING_APPLICATION_ID = Environment.GetEnvironmentVariable("BW_MESSAGING_APPLICATION_ID");

if (BW_ACCOUNT_ID == null || BW_CLIENT_ID == null || BW_CLIENT_SECRET == null || BW_NUMBER == null
|| BW_VOICE_APPLICATION_ID == null || BW_MESSAGING_APPLICATION_ID == null)
{
Console.WriteLine("Please set the environmental variables defined in the README");
Environment.Exit(1);
return;
}

Configuration configuration = new Configuration();
configuration.OAuthClientId = BW_CLIENT_ID;
configuration.OAuthClientSecret = BW_CLIENT_SECRET;

const string SCOPE = "sample";

string Prompt(string text)
{
Console.Write(text);
string? line = Console.ReadLine();
if (line == null)
{
Environment.Exit(1);
}
return line.Trim();
}

string phoneNumber = Prompt("Enter the phone number to send the code to (E.164, e.g. +15554443333): ");
if (!Regex.IsMatch(phoneNumber, @"^\+[1-9]\d{1,14}$"))
{
Console.Error.WriteLine("Phone number must be in E.164 format, e.g. +15554443333");
Environment.Exit(1);
}

string method = Prompt("Send the code by messaging or voice? [messaging]: ").ToLower();
if (method == "")
{
method = "messaging";
}
if (method != "messaging" && method != "voice")
{
Console.Error.WriteLine("Method must be messaging or voice");
Environment.Exit(1);
}

MFAApi mfaApi = new MFAApi(configuration);

CodeRequest codeRequest = new CodeRequest(
to: phoneNumber,
from: BW_NUMBER,
applicationId: method == "voice" ? BW_VOICE_APPLICATION_ID : BW_MESSAGING_APPLICATION_ID,
scope: SCOPE,
message: "Your temporary {NAME} {SCOPE} code is {CODE}",
digits: 6
);

Console.WriteLine($"Sending a code by {method} to {phoneNumber}");
try
{
if (method == "voice")
{
await mfaApi.GenerateVoiceCodeAsync(BW_ACCOUNT_ID, codeRequest);
}
else
{
await mfaApi.GenerateMessagingCodeAsync(BW_ACCOUNT_ID, codeRequest);
}
}
catch (Exception e)
{
Console.Error.WriteLine($"Failed to send code: {e.Message}");
Environment.Exit(1);
}

string code = Prompt("Enter the code you received: ");

bool valid = false;
try
{
VerifyCodeRequest verifyRequest = new VerifyCodeRequest(
to: phoneNumber,
scope: SCOPE,
expirationTimeInMinutes: 3,
code: code
);
valid = (await mfaApi.VerifyCodeAsync(BW_ACCOUNT_ID, verifyRequest)).Valid;
}
catch (Exception e)
{
Console.Error.WriteLine($"Failed to verify code: {e.Message}");
Environment.Exit(1);
}

Console.WriteLine(valid ? "Code verified" : "Code not verified");
Environment.Exit(valid ? 0 : 1);
42 changes: 21 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,44 +4,44 @@
<img src="./icon-mfa.svg" title="Multi-Factor Auth About Page" alt="Multi-Factor Auth About Page"/>
</a>

# Table of Contents
# Table of Contents

- [Multi-Factor Auth CLI](#multi-factor-auth-cli)
- [Table of Contents](#table-of-contents)
- [Description](#description)
- [Pre-Requisites](#pre-requisites)
- [Environmental Variables](#environmental-variables)
- [Running the Application](#running-the-application)
* [Description](#description)
* [Pre-Requisites](#pre-requisites)
* [Running the Application](#running-the-application)
* [Environmental Variables](#environmental-variables)

# Description

This app creates a simple CLI tool used to create and verify multi-factor auth codes using Bandwidth's Multi-Factor Auth API. The app will prompt the user for their phone number, followed by their preferred method of code delivery; either messaging or voice. The app will then text or call the phone number provided with a 6 digit MFA code that the user can enter back into the CLI to verify.
This sample app is a command line tool that sends and verifies multi-factor auth codes using Bandwidth's Multi-Factor Auth API.

The app asks for a phone number in E.164 format and whether to send the code by `messaging` or `voice` (`messaging` if left blank). It then texts or calls that number with a 6 digit code, asks you to enter the code, and checks it. The app exits with status `0` if the code is verified and `1` otherwise.

# Pre-Requisites

In order to use the Bandwidth API users need to set up the appropriate application at the [Bandwidth Dashboard](https://dashboard.bandwidth.com/) and create API tokens.
In order to use the Bandwidth API users need to set up the appropriate applications at the [Bandwidth Dashboard](https://dashboard.bandwidth.com/) and create API tokens.

To create an application log into the [Bandwidth Dashboard](https://dashboard.bandwidth.com/) and navigate to the `Applications` tab. Fill out the **New Application** form selecting the service that the application will be used for (this sample app uses a messaging application).
This app needs two applications, one for each delivery method. To create an application log into the [Bandwidth Dashboard](https://dashboard.bandwidth.com/) and navigate to the `Applications` tab. Fill out the **New Application** form once selecting Messaging, and once selecting Voice. This app doesn't receive any callbacks, so the callback URLs can be left as placeholders.

For more information about API credentials see our [Account Credentials](https://dev.bandwidth.com/docs/account/credentials) page.

# Environmental Variables
# Running the Application

The sample app uses the below environmental variables.
Use the following command to run the application:

```sh
BW_ACCOUNT_ID # Your Bandwidth Account Id
BW_USERNAME # Your Bandwidth API Username
BW_PASSWORD # Your Bandwidth API Password
BW_NUMBER # The Bandwidth phone number involved with this application
BW_VOICE_APPLICATION_ID # Your Voice Application Id created in the dashboard
BW_MESSAGING_APPLICATION_ID # Your Messaging Application Id created in the dashboard
dotnet run
```

# Running the Application
# Environmental Variables

Use the following command to run the application:
The sample app uses the below environmental variables.

```sh
dotnet run
BW_ACCOUNT_ID # Your Bandwidth Account Id
BW_CLIENT_ID # Your Bandwidth API OAuth Client Id
BW_CLIENT_SECRET # Your Bandwidth API OAuth Client Secret
BW_NUMBER # The Bandwidth phone number the code is sent from
BW_VOICE_APPLICATION_ID # Your Voice Application Id created in the dashboard
BW_MESSAGING_APPLICATION_ID # Your Messaging Application Id created in the dashboard
```
6 changes: 3 additions & 3 deletions mfa-cli-csharp.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<RootNamespace>mfa_cli_csharp</RootNamespace>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Bandwidth.Sdk" Version="11.0.0-beta" />
<ItemGroup>
<PackageReference Include="Bandwidth.Sdk" Version="17.3.2" />
</ItemGroup>

</Project>
Loading