Skip to content

Commit

Permalink
dotnet oauth example
Browse files Browse the repository at this point in the history
  • Loading branch information
zenmasterjobo committed Jun 12, 2024
1 parent 8f540d7 commit 3f059c6
Show file tree
Hide file tree
Showing 77 changed files with 74,589 additions and 0 deletions.
27 changes: 27 additions & 0 deletions dotnet/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Ignore Mac .DS_Store file
.DS_Store

# .NET Core
project.lock.json
project.fragment.lock.json
artifacts/
bin/
obj/
out/
TestResults/
*.ncrunch*
*.build.csdef
*.build.csdef

# Ignore config files generated by various tools
appsettings.Development.json

# Ignore VS Code settings folder
.vscode/
.history/

# Ignore logs
*.log

# Ignore sensitive Square credentials
appsettings.json
13 changes: 13 additions & 0 deletions dotnet/DotnetOauthExample.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Square" Version="37.0.1" />
</ItemGroup>

</Project>
25 changes: 25 additions & 0 deletions dotnet/Pages/Callback.cshtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
@page
@model CallbackModel
@{
ViewData["Title"] = "OAuth Callback";
}

<link type="text/css" rel="stylesheet" href="style.css">
<meta name="viewport" content="width=device-width">
<div class="wrapper">
<div class="messages">
<h1>Authorization Succeeded</h1>
<div style='color:rgba(204, 0, 35, 1)'><strong>Caution:</strong> NEVER store or share OAuth access tokens or refresh tokens in clear text.
Use a strong encryption standard such as AES to encrypt OAuth tokens. Ensure the production encryption key is not
accessible to anyone who does not need it.
</div>
<br/>
<div><strong>OAuth access token:</strong>@Model.AccessToken </div>
<div><strong>OAuth access token expires at:</strong> @Model.ExpiresAt </div>
<div><strong>OAuth refresh token:</strong> @Model.RefreshToken </div>
<div><strong>Merchant Id:</strong> @Model.MerchantId </div>
<div><p>You can use this OAuth access token to call Create Payment and other APIs that were authorized by this seller.</p>
<p>Try it out with <a href='https://developer.squareup.com/explorer/square/payments-api/create-payment' target='_blank'>API Explorer</a>.</p>
</div>
</div>
</div>
17 changes: 17 additions & 0 deletions dotnet/Pages/Callback.cshtml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using Microsoft.AspNetCore.Mvc.RazorPages;

public class CallbackModel : PageModel
{
public required string AccessToken { get; set; }
public required string ExpiresAt { get; set; }
public required string MerchantId { get; set; }
public required string RefreshToken { get; set; }

public void OnGet(string accessToken, string expiresAt, string merchantId, string refreshToken)
{
AccessToken = accessToken;
ExpiresAt = expiresAt;
MerchantId = merchantId;
RefreshToken = refreshToken;
}
}
26 changes: 26 additions & 0 deletions dotnet/Pages/Error.cshtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
@page
@model ErrorModel
@{
ViewData["Title"] = "Error";
}

<h1 class="text-danger">Error.</h1>
<h2 class="text-danger">An error occurred while processing your request.</h2>

@if (Model.ShowRequestId)
{
<p>
<strong>Request ID:</strong> <code>@Model.RequestId</code>
</p>
}

<h3>Development Mode</h3>
<p>
Swapping to the <strong>Development</strong> environment displays detailed information about the error that occurred.
</p>
<p>
<strong>The Development environment shouldn't be enabled for deployed applications.</strong>
It can result in displaying sensitive information from exceptions to end users.
For local debugging, enable the <strong>Development</strong> environment by setting the <strong>ASPNETCORE_ENVIRONMENT</strong> environment variable to <strong>Development</strong>
and restarting the app.
</p>
27 changes: 27 additions & 0 deletions dotnet/Pages/Error.cshtml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
using System.Diagnostics;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;

namespace DotnetOauthExample.Pages;

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
[IgnoreAntiforgeryToken]
public class ErrorModel : PageModel
{
public string? RequestId { get; set; }

public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);

private readonly ILogger<ErrorModel> _logger;

public ErrorModel(ILogger<ErrorModel> logger)
{
_logger = logger;
}

public void OnGet()
{
RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
}
}

9 changes: 9 additions & 0 deletions dotnet/Pages/Index.cshtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
@page
@model IndexModel
@{
ViewData["Title"] = "Home page";
}

<div class="text-center">
<p><a class="btn btn-primary" href="/authorize">Authorize</a></p>
</div>
19 changes: 19 additions & 0 deletions dotnet/Pages/Index.cshtml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;

namespace DotnetOauthExample.Pages;

public class IndexModel : PageModel
{
private readonly ILogger<IndexModel> _logger;

public IndexModel(ILogger<IndexModel> logger)
{
_logger = logger;
}

public void OnGet()
{

}
}
43 changes: 43 additions & 0 deletions dotnet/Pages/Shared/_Layout.cshtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>@ViewData["Title"] - DotnetOauthExample</title>
<link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.min.css" />
<link rel="stylesheet" href="~/css/site.css" asp-append-version="true" />
<link rel="stylesheet" href="~/DotnetOauthExample.styles.css" asp-append-version="true" />
</head>
<body>
<header>
<nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
<div class="container">
<a class="navbar-brand" asp-area="" asp-page="/Index">DotnetOauthExample</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target=".navbar-collapse" aria-controls="navbarSupportedContent"
aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="navbar-collapse collapse d-sm-inline-flex justify-content-between">
</div>
</div>
</nav>
</header>
<div class="container">
<main role="main" class="pb-3">
@RenderBody()
</main>
</div>

<footer class="border-top footer text-muted">
<div class="container">
&copy; 2024 - DotnetOauthExample
</div>
</footer>

<script src="~/lib/jquery/dist/jquery.min.js"></script>
<script src="~/lib/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
<script src="~/js/site.js" asp-append-version="true"></script>

@await RenderSectionAsync("Scripts", required: false)
</body>
</html>
48 changes: 48 additions & 0 deletions dotnet/Pages/Shared/_Layout.cshtml.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/* Please see documentation at https://docs.microsoft.com/aspnet/core/client-side/bundling-and-minification
for details on configuring this project to bundle and minify static web assets. */

a.navbar-brand {
white-space: normal;
text-align: center;
word-break: break-all;
}

a {
color: #0077cc;
}

.btn-primary {
color: #fff;
background-color: #1b6ec2;
border-color: #1861ac;
}

.nav-pills .nav-link.active, .nav-pills .show > .nav-link {
color: #fff;
background-color: #1b6ec2;
border-color: #1861ac;
}

.border-top {
border-top: 1px solid #e5e5e5;
}
.border-bottom {
border-bottom: 1px solid #e5e5e5;
}

.box-shadow {
box-shadow: 0 .25rem .75rem rgba(0, 0, 0, .05);
}

button.accept-policy {
font-size: 1rem;
line-height: inherit;
}

.footer {
position: absolute;
bottom: 0;
width: 100%;
white-space: nowrap;
line-height: 60px;
}
2 changes: 2 additions & 0 deletions dotnet/Pages/Shared/_ValidationScriptsPartial.cshtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<script src="~/lib/jquery-validation/dist/jquery.validate.min.js"></script>
<script src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js"></script>
3 changes: 3 additions & 0 deletions dotnet/Pages/_ViewImports.cshtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
@using DotnetOauthExample
@namespace DotnetOauthExample.Pages
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
3 changes: 3 additions & 0 deletions dotnet/Pages/_ViewStart.cshtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
@{
Layout = "_Layout";
}
100 changes: 100 additions & 0 deletions dotnet/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
using Square;
using Square.Models;
using Square.Exceptions;



var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddRazorPages();

// Load configuration from appsettings.json
builder.Configuration.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true);

var app = builder.Build();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();

app.MapRazorPages();

app.MapGet("/authorize", async context =>
{
var configuration = context.RequestServices.GetRequiredService<Microsoft.Extensions.Configuration.IConfiguration>();
var applicationId = configuration["Square:ApplicationId"];
var redirectUri = configuration["Square:RedirectUri"];
var state = Guid.NewGuid().ToString(); // CSRF protection

var baseUrl = configuration["Square:Environment"] == "Production" ? "https://connect.squareup.com" : "https://connect.squareupsandbox.com";
var authorizationUrl = $"{baseUrl}/oauth2/authorize?client_id={applicationId}&response_type=code&scope=MERCHANT_PROFILE_READ&state={state}&redirect_uri={Uri.EscapeDataString(redirectUri)}";


context.Response.Redirect(authorizationUrl);
});

app.MapGet("/callback", async context =>
{
var request = context.Request;
var code = request.Query["code"];
var state = request.Query["state"];

if (!string.IsNullOrEmpty(code))
{
// Exchange code for access token
var configuration = context.RequestServices.GetRequiredService<Microsoft.Extensions.Configuration.IConfiguration>();
var client = new SquareClient.Builder()
.Environment(Square.Environment.Sandbox)
.Build();

var body = new ObtainTokenRequest.Builder(clientId: configuration["Square:ApplicationId"], grantType: "authorization_code")
.ClientSecret(configuration["Square:ApplicationSecret"])
.Code(code)
.RedirectUri(configuration["Square:RedirectUri"])
.Build();

try
{
var result = await client.OAuthApi.ObtainTokenAsync(body: body);
if (result.AccessToken != null)
{
var accessToken = result.AccessToken;
var refreshToken = result.RefreshToken;
var expiresAt = result.ExpiresAt;
var merchantId = result.MerchantId;

var redirectUrl = $"/Callback?accessToken={accessToken}&refreshToken={refreshToken}&expiresAt={expiresAt}&merchantId={merchantId}";
context.Response.Redirect(redirectUrl);
}
else
{
Console.WriteLine("Failed to obtain access token: ", result);
context.Response.Redirect("/");
}
}
catch (ApiException e)
{
Console.WriteLine("Failed to obtain access token: ", e);
context.Response.Redirect("/");
}
}
else
{
context.Response.Redirect("/");
}
});

app.Run();
Loading

0 comments on commit 3f059c6

Please sign in to comment.