Building an OAuth2 Enabled Web Application with ChatGPT and GPT 4

Dave Arlin
Eviden Data Science and Engineering Community
14 min readApr 10, 2023
Robot/Human Nightclub Image Generated by Bing / DALL-E

Off to the Nightclub with ChatGPT

Over the past week, I found myself staying up late at night while I embarked on a journey to build a simple yet functional platform using Microsoft’s Identity platform, which I’ve named “Clubbing with ChatGPT.” This platform features a web UI that simulates a user attempting to enter a nightclub. My objective was to leverage Microsoft’s Identity platform, specifically IdentityServer4, to achieve this. The experiment aimed to have ChatGPT with GPT4 generate three distinct applications:

  1. An ASP.NET Web API functioning as an OpenID Connect Identity Server, serving custom login pages based on the OAuth2 client seeking authorization.
  2. An ASP.NET Web API serving as a Resource API, providing “Strobe Light” data to consumers upon request, as long as their JWT, created by the aforementioned Identity Server, contained the necessary scope.
  3. An ASP.NET Blazor WASM application that simulates the user being outside the nightclub. Upon attempting to “enter,” users are prompted to log in. Once authorized, they are transported to a page representing the club’s dance floor. This application also features two additional pages, one for exclusive “VIP” users and another for the “Club Manager.” Access to these pages requires specific user roles. Moreover, the top navigation bar’s color changes according to the user’s role.

The results were not entirely perfect. I think it’s safe to say that ChatGPT won’t complete 100% of all your work for you, but it sure can help.

I divided the above applications up into three separate prompts within their own context in ChatGPT.

Prompt 1 — Identity Server

Build me a central Identity Server auth service using ASP.NET Web API.

· Use only the built in templates from the dotnet CLI.

· This service will be the central identity platform and use the OpenID Connect standard to supply access tokens to various clients.

· This service will use EntityFramework Migrations and SQL Server. The appsettings.Development.json should contain a connection string pointing to “localhost” and using a trusted connection and trusting the server certificate.

· This app must run on https at port 5001. Insecure http is not allowed. Update the properties.json to accommodate this.

· This app will use SCSS for styling, I already have the necessary components installed to compile SCSS to CSS.

· This application will not have a Startup.cs, instead it will have a Program.cs using top level statements.

· This service will begin by allowing two OAuth2 clients, “chatgpt-clubbin-web-client” and “chatgpt-clubbin-mobile-client”. They will both use the authorization code grant type with PKCE.

· When an auth challenge is presented to a client using the “chatgpt-clubbin-web-client”, the user should be redirected to a custom login page. Any other OAuth2 clients, including the “chatgpt-clubbin-mobile-client” should use the default IdentityServer4 provided login UI.

· The “chatgpt-clubbin-web-client” login page should be styled to with a full screen background image. The login form should be horizontally and vertically centered. The login form should have an “<h2>” that says “Are you on the list?” with a username and password textbox underneath it with black background, white borders and white text. There should be a light gray watermark for username and password and no labels for those textboxes. All this content should appear within a translucent <div> that is dark gray.

· A custom “club-access” scope should be associated with both OAuth2 clients in addition to the default “openid” and “profile” and “offline_access” scopes.

· These clients and scopes should be seeded in the database, not in memory.

· Cors origin for the “chatgpt-clubbin-web-client” will be “https://localhost:6001” and also stored in the database.

· The following users should be seeded in the database. Make sure the password policy allows for these shortened passwords.

1. username: “john”, password: “doe”, first name: “John”, last name: “Doe”, role: “Club Attendee”

2. username: “jane”, password: “doe” — first name: “Jane”, last name: “Doe”, role: “Club Attendee”

3. username: “mrbig”, password: “boss”, first name: “Big”, last name: “Boss”, role: “Club Manager”

4. username: “vip”, password “clubber”, first name: “VIP”, last name: “Clubber”, role: “VIP”

· There will be future Resource APIs created later that will need to validate the JWTs issued from this service. The first of these will run at “https://localhost:5002

In certain instances, I provided very specific instructions, such as using EF Migrations, SQL Server, particular users, roles, port numbers, OAuth2 clients, and scopes. I also detailed the exact text I wanted displayed on the login form. For those who have worked with the Identity Platform, it’s no secret that there have been numerous changes to the IdentityServer4 library over the years. While it remains open source, it’s now also a commercial product under Duende Software, which is the sole official source for ongoing support. Additionally, Microsoft’s identity libraries employ this library and add a few extra features.

ChatGPT struggled with differentiating between the required references and writing the necessary code for a custom login page tailored to a specific OAuth2 client. Ultimately, I had to take the generated code, refactor, and rewrite a significant portion of it. It’s worth noting that ChatGPT’s training data only extends until 2021, which led to some outdated suggestions, such as referencing .NET 6 framework libraries or older .NET Core templates that are no longer current.

Nevertheless, ChatGPT was useful in providing a general sense of what needed to be done and gave me 13 Steps, in very specific detail, to do so.

The 13 step response from my first prompt

I needed to expand on my initial prompt with a few more specific instructions regarding the custom login page for a particular OAuth2 client. During this process, it became evident that certain aspects of my original prompt were overlooked or disregarded, such as the SCSS generation I had mentioned and assumptions about the existence of specific files that were never present. I also encountered a few runtime errors and sought ChatGPT’s assistance to address them. Surprisingly, ChatGPT was quite adept at helping me resolve these issues. In most instances, the problem stemmed from missing registrations in the Program.cs class for certain types used throughout the code. It’s intriguing that ChatGPT knew how to rectify these problems, yet it failed to recognize that they would arise when it initially provided the code.

Prompt 2 — Resource API

Create an ASP.NET Web API project named “Acme.StrobeLight.API”. Provide the full source code, styling and command line commands with the following details. If this does not fit in a single response, provide the subsequent prompts for me to accomplish this.

· This service will be a Resource API that needs to validate JWTs issued by an existing Identity Server called “Acme.IdentityServer” which is an ASP.NET Web API using IdentityServer4. Acme.IdentityServer runs at https://localhost:5001.

· This service will run on https locally at https://localhost:5002

· This service will provide data to a Blazor web application running at https://localhost:6001

· This service will not have a Startup.cs, instead it will have a Program.cs using top level statements.

· This service will use EntityFramework Migrations and SQL Server. The appsettings.Development.json should contain a connection string pointing to “localhost” and using a trusted connection and trusting the server certificate.

· The following “StrobeLight” data should be seeded in the database.

name: Moving Head Light Beams, quantity: 4, maxQuantity: 5

name: Pro Strike Array 4-LED Strobe / Blinder Effect Light, quantity: 2, maxQuantity: 4

name: Chauvet DJ Helicopter Q6 RGBW Beam/Strobe/Laser, quantity: 2, maxQuantity 3

· This service should expose the necessary REST endpoints that allow clients to update the quantity of any existing “StrobeLight” records. This quantity may not be less than 0 or greater than the “maxQuantity” value defined for the StrobeLight being updated.

· There should also be an endpoint to retrieve the full list of all StrobeLight entities. Users may not add or remove new StrobeLight entities at this time.

I’ll leave out the responses from ChatGPT and just show some of the results.

Acme.StrobeLight.API project structure created by ChatGPT’s response
Swagger UI showcasing the two endpoints created for the Acme.StrobeLight.API
The “StrobeLightDb” database created via EF Migrations and code provided by ChatGPT’s response

The development of this particular component was significantly smoother, as it involved a relatively simple and straightforward REST API. This API exposed only two endpoints: one for retrieving a list of all Strobe Lights and another for updating the quantity of a specific strobe light.

To ensure proper implementation, I only needed to send a few additional prompts. These guided ChatGPT in adding the correct CORS policy for my frontend application and incorporating the “club-access” scope, which was essential for validating the JWT sent by my frontend application.

Prompt 3 — Web Application

Create a Blazor WASM standalone project named “ChatGPT Clubbing”. Provide the full source code, styling and command line commands with the following details. If this does not fit in a single response, provide the subsequent prompts for me to accomplish this.

· SCSS will be used for styling the HTML. I already have the necessary tools set up to auto compile scss to css.

· This application should use the .NET 7 framework

· This application will run on https at https://localhost:6001

· This application will not have a Startup.cs, instead it will have a Program.cs using top level statements.

· All pages should have their content horizontally and vertically centered with a black background, white borders and white text. All text should be white, buttons should be borderless with white text. When a user hovers over a button, the background color of the button should turn a dark gray. Any content on a page should be contained in a translucent <div> with a dark gray background.

· The home page will be titled “Outside the Club”. This page should allow anonymous users to access it. This page will have a full screen video taking up the background. This page should additionally have text that says “You’re outside the club. If you’re on the list, head on in!” Under this text should be a button that says “Come In”.

· When the user clicks the “Come In” button, it should navigate to a page named “Club Floor”. This page will require the user to be authorized. If the user is not authorized, they should be navigated to a login form handled by an existing ASP.NET Web API Identity Server called “Acme.IdentityServer” using OpenID Connect.

· The identity authority Web API’s root url is https://localhost:5001. This application will be authenticated via an OAuth2 client named “chatgpt-clubbin-web-client” using the authorization code grant and passing in the “club-access” scope. There are certain roles that can be returned from this identity authority, they are “Club Attendee”, “VIP”, and “Club Manager”.

· Once logged in and authorized, the user will be redirected to the “Club Floor” page.

· The “Club Floor” page will have a video that takes up the whole screen. The text on this screen should display a few paragraphs about having fun at the club and enjoying the excellent music and cocktails. Under this text should be a list of “Strobe Lights” including their name and quantity. These can be listed in a simple table with columns for “Name” and “Quantity” with a sub header above the table named “Check out the awesome lighting!”. This data will be retrieved from an already existing “Acme.StrobeLight.API” resource API at https://localhost:5002 from an endpoint named “/strobelights” using an HTTP GET and only passing in the JWT from the Acme.IdentityServer as a bearer token.

· When a user is authenticated, there should be a navigation bar that appears at the top of the “ChatGPT Clubbin” app. This navigation bar should have a dark gray background with white text and white link styles. When you hover over a link, it should give the link text a slightly lighter gray background than the top navigation background color. This navigation bar should not appear if the user is not authenticated.

· The navigation bar should have a link that says “Go Outside” aligned to the left with a margin of 10px from the left border. This should navigate to the “Outside the Club” page.

· The navigation bar should have a link that says “Club Floor” 10 px from the left of the “Go Outside” link that navigates to the “Club Floor” page.

· The navigation bar should have a “Call it a Night” link at the far right of the top nav with a 10px margin from the right border. This should log the user out. Then the user will be navigated to the “Outside the Club” screen.

· When a “VIP” user logs in, the nav bar should instead have a dark gold color background This user will have an additional link 10px to the right of the “Club Floor” link called “VIP Area”. This link will take this user to a new page called “Behind the Ropes”. This page will have a different video in the background and different text containing some paragraphs about the perks of getting VIP access inside of a typical night club such as bottle service and a spectacular view.

· When a “Club Manager” user logs in, the nav bar should have a platinum background color. This user will have an additional link 10px to the right of the “Club Floor” link called “Back Office”. This link will take this user to a new page called “Back Office”. This page will contain a list of all available “Strobe Lights” obtained through the “/strobelights” endpoint on the “Acme.StrobeLight.API” api.

· In the “backoffice” page, the user will also be able to change the quantity of each strobe light via another endpoint defined in the existing “Acme.StrobeLight.API” at the /strobelights endpoint via an HTTP Put, passing in the StrobeLight Id and Quantity. The user may not pass in a value that exceeds the MaxQuantity property defined for each strobe light, returned from the previous call to “/strobelights” via the HTTP Get. Include client side validation in the “backoffice” page. In the table of the list of strobe lights, one of the columns should use a textbox instead of a label to display the Quantity. Under this text box should be a smaller label that displays what the MaxQuantity is with text like “Max: [MaxQuantity]” where MaxQuantity is returned from the HTTP Get to /strobelights.

· As soon as the user starts to make changes, a “Save” checkbox button should appear to the right of this table as well a “Cancel” x button to its right. Changes to this list should not be submitted to the Strobe Light API until the end user clicks the “Save” button for each row. Once the changes are persisted to the database, the “Save” and “Cancel” button should no longer appear for that row. If the user clicks the “Cancel” button, any changes the end user made to that row should revert back to the original list when first loaded. Then, both the “Save” and “Cancel” buttons should disappear. When the “Save” operation succeeds, text should appear where the “Save” and “Cancel” buttons were that says “You got it boss!”. This text should disappear after 5 seconds.

I must admit that creating this project with ChatGPT wasn’t without its challenges. I had to follow up with numerous prompts and even restart the process about 10 times, fine-tuning my communication with ChatGPT. On more than one occasion, ChatGPT informed me that my request was overly complicated. Initially, I tried to combine all three application requests into a single prompt, thinking that approach would be more efficient. However, I discovered that dividing them into three separate prompt contexts yielded better results.

Ultimately, by combining ChatGPT’s responses and making some of my own adjustments, I managed to achieve most of what I had initially set out to accomplish.

Clubbing with ChatGPT Home Page — Image Courtesy of Bing Image Creator w/DALL-E
Custom Login Page
Club Floor Page with a standard user
VIP Nav Bar
Club Manager Nav Bar
The Back Office page

No, ChatGPT did not find these images for me, but it did provide the placeholder video & image URLs for me to fill in. I did some basic Google image searching and also tried to see what Bing Image Creator and DALL-E could get me.

This final component of the experiment was both remarkable and chaotic. It was interesting to observe ChatGPT’s guidance on creating the “.razor” pages and their corresponding CSS/SCSS, as I had requested. The AI did a great job with the full-screen background image/video styling and the navbar theme. While it was initially puzzled by my “Club Manager” admin functionality, I managed to clarify most of it with subsequent prompts. I had to manually tweak a fair amount around the networking side. But, on the UI side of the Back Office page form, ChatGPT even implemented a 5-second delay to display the text confirming my save succeeded as I requested.

The messy part involved numerous incorrect references, specifically around the Identity libraries. There were also several updates to files like “App.razor,” and custom implementations of “AuthenticationStateProvider.” Things became overly complicated pretty quick. ChatGPT appeared uncertain about the files generated by the initial “dotnet new” commands on the built-in ASP.NET Web API template and seemed to overlook my explicit mention of “Top Level Statements” in Program.cs. Consequently, I had to carry out substantial refactoring, and ChatGPT offered numerous apologies with new suggestions. Some of these worked, some didn’t.

In short, no it didn’t give me 100% of all the code I needed to accomplish my full ask, but it probably gave me about 80%. It encouraged me to think more critically critical and taught me to ask better questions. At times, I felt like I relied less on my own problem-solving skills while tweaking ChatGPT’s responses than I would have when working on and debugging code myself. However, I’m still learning how to harness ChatGPT’s potential effectively.

My grand plan was to store my ChatGPT prompts in source control as an even higher level of “code”. However, I discovered that even when resetting the prompt context, the responses could vary dramatically, with different libraries, file names, and approaches to the same task. This unpredictability is both fascinating, maddening, and slightly terrifying, so I abandoned that idea.

I’m eager to hear if others have had similar experiences while working on complex projects and if anyone has discovered tips or tricks for obtaining better or more consistent results.

--

--

Dave Arlin
Eviden Data Science and Engineering Community

Digital Transformation Leader, Strong Believer in People and Upskilling