Authentication with React and .NET Core using Okta (openID Connect)

React verifies user with okta, Okta redirects back with a code, This is then shared by .NetCore which then is verified by okta.
Open Id Connect Flow for React and .NET Core
Click Create New App
From the wizard, choose the “Single-Page App” option for the React app.
and click “Create”
In “General Settings”, enter the following values, and click “Save”
npx create-react-app okta-tutorialnpm install @okta/okta-signin-widgetnpm install @okta/okta-auth-js @okta/okta-react react-router-domnpm install dotenv — savenpm install semantic-ui-react semantic-ui-css
Create a “.okta.env” file in root directory
Add the following and fill the domain as ISSUER and client id
ISSUER=https://{ okta-domain }/oauth2/default
CLIENT_ID={ CLIENT_ID okta }
Create config.js file in directory src/config.js Add the following code
const CLIENT_ID = process.env.CLIENT_ID || 'Client id okta ';
const ISSUER = process.env.ISSUER || 'https://{ okta-domain }/oauth2/default';
const OKTA_TESTING_DISABLEHTTPSCHECK = process.env.OKTA_TESTING_DISABLEHTTPSCHECK || false;
const REDIRECT_URI = `${window.location.origin}/login/callback`;

// eslint-disable-next-line
export default {
oidc: {
clientId: CLIENT_ID,
issuer: ISSUER,
redirectUri: REDIRECT_URI,
scopes: ['openid', 'profile', 'email'],
pkce: true,
disableHttpsCheck: OKTA_TESTING_DISABLEHTTPSCHECK,
},
resourceServer: {
messagesUrl: 'http://localhost:8000/api/messages',
},
};
Edit App.js component in file directory src/App.js Add the following code
import { OktaAuth, toRelativeUrl } from '@okta/okta-auth-js';
import { Security, SecureRoute, LoginCallback } from '@okta/okta-react';
import { Route, Switch, useHistory } from 'react-router-dom';
import { Container } from 'semantic-ui-react';
import config from './config';
import './App.css';
import Home from './Home';
import Messages from './Messages';
import Navbar from './Navbar';

const oktaAuth = new OktaAuth(config.oidc);

function App() {

const history = useHistory();
const restoreOriginalUri = async (oktaAuth, originalUri) => {
history.replace(toRelativeUrl(originalUri, window.location.origin));
};

return (
<Security oktaAuth={oktaAuth} restoreOriginalUri={restoreOriginalUri}>
<Navbar />
<Container text style={{marginTop: '7em'}}>
<Switch>
<Route path="/" exact={true} component={Home}/>
<Route path="/login/callback" component={LoginCallback}/>
<SecureRoute path="/messages" component={Messages}/>
</Switch>
</Container>
</Security>
);
}

export default App;
Edit Index.js component in file directory src/Index.js Add the following code
import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter as Router } from 'react-router-dom';
import 'semantic-ui-css/semantic.min.css';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';

ReactDOM.render(
<Router>
<App />
</Router>,
document.getElementById('root')
);

reportWebVitals();
Create Navbar.js component in file directory src/Navbar.js Add the following code
import { useOktaAuth } from '@okta/okta-react';
import { Link } from 'react-router-dom';
import { Container, Icon, Menu } from 'semantic-ui-react';
import React from 'react'

const Navbar = () => {
const { authState, oktaAuth } = useOktaAuth();

const login = async () => oktaAuth.signInWithRedirect();
const logout = async () => oktaAuth.signOut();
return (
<div>
<Menu fixed="top" inverted>
<Container>
<Menu.Item header>
<Link to="/">Okta-React Project</Link>
</Menu.Item>
{authState.isAuthenticated && (
<Menu.Item id="messages-button">
<Icon name="mail outline" />
<Link to="/messages">Messages</Link>
</Menu.Item>
)}
{authState.isAuthenticated && (
<Menu.Item id="logout-button" onClick={logout}>Logout</Menu.Item>
)}
{!authState.isPending && !authState.isAuthenticated && (
<Menu.Item onClick={login}>Login</Menu.Item>
)}
</Container>
</Menu>
</div>
)
}
export default Navbar
Create Home.js component in file directory src/Home.js Add the following code
import { useOktaAuth } from '@okta/okta-react';
import React, { useState, useEffect } from 'react';

const Home = () => {
const { authState, oktaAuth } = useOktaAuth();
const [userInfo, setUserInfo] = useState(null);

useEffect(() => {
if (!authState.isAuthenticated) {
// When user isn't authenticated, forget any user info
setUserInfo(null);
} else {
oktaAuth.getUser().then((info) => {
setUserInfo(info);
});
}
}, [authState, oktaAuth]); // Update if authState changes
return (
<div>

Home Page

{authState.isAuthenticated && userInfo
&& (
<div>
<p>
Welcome ,&nbsp;
{userInfo.name}
!
</p>
<p>
Succesfully Logged In at Client Side using Open Id Connect
</p>
<h5>Access Token is</h5>
<h5>{authState.accessToken.accessToken}</h5>
</div>
)}

</div>
)
}

export default Home
Create Messages.js component in file directory src/Messages.js Add the following code
import { useOktaAuth } from '@okta/okta-react';
import React, { useState, useEffect } from 'react';
import { Header, Icon, Message, Table, Container } from 'semantic-ui-react';
import config from './config';

const Messages = () => {
const { authState, oktaAuth } = useOktaAuth();
const [messages, setMessages] = useState(null);
const [messageFetchFailed, setMessageFetchFailed] = useState(false);

useEffect(() => {
if (authState.isAuthenticated) {
const accessToken = oktaAuth.getAccessToken();
fetch(config.resourceServer.messagesUrl, {
headers: {
Authorization: `Bearer ${accessToken}`,
},
})
.then((response) => {
if (!response.ok) {
return Promise.reject();
}
return response.json();
})
.then((data) => {
let index = 0;
const formattedMessages = data.messages.map((message) => {
const date = new Date(message.date);
const day = date.toLocaleDateString();
const time = date.toLocaleTimeString();
index += 1;
return {
date: `${day} ${time}`,
text: message.text,
id: `message-${index}`,
};
});
setMessages(formattedMessages);
setMessageFetchFailed(false);
})
.catch((err) => {
setMessageFetchFailed(true);
console.error(err);
});
}
}, [authState, oktaAuth]);

const possibleErrors = [
'Server is not responding',
'Or Server may not be authorized'
];

return (
<Container text style={{marginTop: '7em'}}>
<Header as="h1">
<Icon name="mail outline" />
My Messages
</Header>
{messageFetchFailed && <Message error header="Failed to fetch messages. Please verify the following:" list={possibleErrors} />}
{!messages && !messageFetchFailed &&
<div className="ui active dimmer">
<div className="ui large text loader">Loading Messages</div>
</div>}
{messages
&& ( <div>
<Table>
<thead>
<tr>
<th>Date</th>
<th>Message</th>
</tr>
</thead>
<tbody>
{messages.map((message) => (
<tr id={message.id} key={message.id}>
<td>{message.date}</td>
<td>{message.text}</td>
</tr>
))}
</tbody>
</Table>
</div>
)}
</Container>
);
};

export default Messages;
dotnet new webapi -n okta-Server
Go to Properties/launchSettings.json and make following changes
{
"$schema": "http://json.schemastore.org/launchsettings.json",
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:8000/"
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": false,
"launchUrl": "http://localhost:8000/",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"okta_Server": {
"commandName": "Project",
"launchBrowser": false,
"applicationUrl": "http://localhost:8000/",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}
In appsettings.json add the okta domain required
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*",
"Okta": {
"OktaDomain": "https://{ okta-domain }/"
}
}
After installing the latest version you need to make changes in the Startup.cs file
Add the following code in “ConfiguringServices” method and before “services.AddControllers()”
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Okta.AspNetCore;

namespace okta_Server
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}

public IConfiguration Configuration { get; }

// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddCors(options =>
{
// The CORS policy is open for testing purposes. In a production application, you should restrict it to known origins.
options.AddPolicy(
"AllowAll",
builder => builder.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader());
});
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = OktaDefaults.ApiAuthenticationScheme;
options.DefaultChallengeScheme = OktaDefaults.ApiAuthenticationScheme;
options.DefaultSignInScheme = OktaDefaults.ApiAuthenticationScheme;
})
.AddOktaWebApi(new OktaWebApiOptions()
{
OktaDomain = Configuration["Okta:OktaDomain"],
});

services.AddAuthorization();

services.AddControllers();
}

// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}

app.UseHttpsRedirection();

app.UseRouting();

app.UseCors("AllowAll");

app.UseAuthentication();

app.UseAuthorization();

app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
}
After that in Configure method Add the code in similar manned as in above code.
using System;
using System.Linq;
using System.Security.Claims;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Cors;
using Microsoft.AspNetCore.Mvc;

namespace okta_Server.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class MessageController : ControllerBase
{
[Authorize]
[HttpGet]
[Route("~/api/messages")]
[EnableCors("AllowAll")]

public JsonResult Get()
{
var principal = HttpContext.User.Identity as ClaimsIdentity;

var login = principal.Claims
.SingleOrDefault(c => c.Type == ClaimTypes.NameIdentifier)
?.Value;

return new JsonResult(new
{
messages = new dynamic[]
{
new { Date = DateTime.Now, Text = "Sending this Message from Server" },
new { Date = DateTime.Now, Text = "Verified the access Token" },
new { Date = DateTime.Now, Text = "You are now Authenicated by okta" },
new { Date = DateTime.Now, Text = "I hope this was helpful" },
},
});
}
}
}
dotnet watch run          ( inside .net folder )npm start                 ( inside React folder )
The home Page notice there is only login option
After Clicking on Login you redirect to Okta page
Now that you are Logged in you can see Messages and a Logout tab
Messages Sent Back From the Server to The Client.

--

--

--

I am a Software Developer, passionate about Embedded systems by making various projects. Other than that I love to play Football and Badminton.

Love podcasts or audiobooks? Learn on the go with our new app.

Recommended from Medium

5 JavaScript Features That Are Introduced In ES2021

ES 2021

Basics of Javascript · String · codePointAt() (method)

Basics of Javascript · String · substring() (method)

Angular Basics-4

Top 10 Buzzwords of 2022

Learn GatsbyJS by creating a tourism site -7

Create a Sketchware pro Blocks viewer with JSON blocks.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Ankit Khandeparkar

Ankit Khandeparkar

I am a Software Developer, passionate about Embedded systems by making various projects. Other than that I love to play Football and Badminton.

More from Medium

How to use Notion API from Typescript Azure Function

CloudFront Signed URLs | AWS + .NET Core | Part 3

Writing Serverless Business Logic With Hasura Actions and Azure Functions

Deploying a Frontend web app to Azure Static Web App with Pulumi