<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Anna Parissi on Medium]]></title>
        <description><![CDATA[Stories by Anna Parissi on Medium]]></description>
        <link>https://medium.com/@annaparissi_89713?source=rss-95fbf524e0f4------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*IecUY0FWItdtmhAYkoPU9A.jpeg</url>
            <title>Stories by Anna Parissi on Medium</title>
            <link>https://medium.com/@annaparissi_89713?source=rss-95fbf524e0f4------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Mon, 18 May 2026 02:46:47 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@annaparissi_89713/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com" rel="hub"/>
        <item>
            <title><![CDATA[Creating a secure spring-boot & react app using Okta]]></title>
            <link>https://medium.com/@annaparissi_89713/creating-a-secure-spring-boot-react-app-using-okta-3f80ffc5fa6b?source=rss-95fbf524e0f4------2</link>
            <guid isPermaLink="false">https://medium.com/p/3f80ffc5fa6b</guid>
            <category><![CDATA[okta]]></category>
            <category><![CDATA[oauth2]]></category>
            <category><![CDATA[react]]></category>
            <category><![CDATA[antd]]></category>
            <category><![CDATA[spring-boot]]></category>
            <dc:creator><![CDATA[Anna Parissi]]></dc:creator>
            <pubDate>Tue, 24 Jan 2023 09:50:46 GMT</pubDate>
            <atom:updated>2023-01-26T12:19:33.595Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/666/1*mTo707YvLaeTy1NKbaifAQ.png" /></figure><p>A react frontend application needs to handle situations where a user tries to access a private server resource. To accomplish that, implementing User Authentication is the first thing that comes in mind. Among others that means implementing a Login/Logout functionality, retrieving user information and protecting our application routes.</p><p>On the other side our backend application needs to ensure that private resources are served to authenticated users as well. By implementing a spring-boot app and adding spring-security which provides multiple features such as Authorization, Single sign-on, LDAP etc, is one way to start with.</p><p>Okta is an identity management service with Single Sign-On (SSO), Active Directory (AD) and LDAP integration, multifactor authentication (MFA), mobile identity management, configurable rules for corporate security being just a few of its capabilities. For more information regarding Okta’s features visit: <a href="https://developer.okta.com/docs/concepts/how-okta-works/">https://developer.okta.com/docs/concepts/how-okta-works/</a></p><p>Combining these three together can help you create a secure application with Single Sign-On access, which greatly improves usability for employees. In this article we will leverage Okta’s packages to secure our application with OpenID Connect on top of OAuth 2.0 protocol.</p><h3>1. Setup Okta App Integration</h3><p>To start with, you’ll need an Okta developer account to setup your authorization server. Create an account at <a href="https://developer.okta.com/signup/">https://developer.okta.com/signup/</a></p><p>Login and setup the Okta integration app as follows:</p><p>From the menu select Applications → Create App Integration</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/905/1*Uv7mPVw_nftePI8bfLFOhw.jpeg" /><figcaption>Okta: Create App Integration</figcaption></figure><p>For <strong>Sign-in method </strong>select OIDC — OpenID Connect, for <strong>Application type </strong>select <strong>Single-Page Application</strong> and click Next.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/905/1*PpRgbpaErpjrnorIt97f8w.jpeg" /><figcaption>Okta: App Integration Sign-in method</figcaption></figure><p>In the <strong>General Settings</strong> tab enter the <strong>App integration name </strong>and select <strong>Grant type </strong>→ <strong>Authorization Code </strong>, required to enable OAuth2 authentication.</p><p>Set the <strong>Sign-in redirect URIs </strong>to: <a href="http://localhost:3000/login/callback">http://localhost:3000/login/callback</a></p><p>Set the <strong>Sign-out redirect URIs </strong>to: <a href="http://localhost:3000">http://localhost:3000</a></p><p>When using the OpenID Connect sign-in method, we’ll be redirected to an Okta hosted sign-in widget. That’s why we’ll need a callback URL where Okta will be able to return the user’s details back to our application.</p><p><a href="http://localhost:3000">http://localhost:3000</a> is where our react app will be served. You can also add multiple URIs if you need access from different environments, for example dev or prod by clicking the <strong>Add URI button</strong>.</p><p>In the Assignments tab select: <strong>Allow everyone in your organization to access</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/905/1*yiiBzYnIq2-NgH6RVCpBMA.jpeg" /><figcaption>Okta: App Integration General Settings</figcaption></figure><p>By clicking save, a Client ID will be generated. This is a Public identifier for the client that is required for all OAuth flows and we’ll need that in the next steps when configuring our spring boot app along with our client react app.</p><h3>2. Setup Spring Boot App</h3><p>Create a new spring boot application. For this example, we’ll use Java 17 and spring-boot 3.0. By adding the following directories we will create a simple REST endpoint to fetch some data.</p><pre>src/<br>┣ main/<br>┃ ┣ java/<br>┃ ┃ ┗ com/<br>┃ ┃   ┗ example/<br>┃ ┃ ┃   ┗ server/<br>┃ ┃ ┃ ┃   ┣ config/<br>┃ ┃ ┃ ┃ ┃ ┃ ┗ WebSecurityConfig.java<br>┃ ┃ ┃ ┃   ┣ controller/<br>┃ ┃ ┃ ┃ ┃ ┃ ┣ StatusController.java<br>┃ ┃ ┃ ┃ ┃ ┃ ┗ TaskController.java<br>┃ ┃ ┃ ┃   ┣ dto/<br>┃ ┃ ┃ ┃ ┃ ┃ ┗ Task.java<br>┃ ┃ ┃ ┃   ┣ service/<br>┃ ┃ ┃ ┃ ┃ ┃ ┗ TaskService.java<br>┃ ┃ ┃ ┃   ┗ ServerApplication.java<br>┃ ┗ resources/<br>┃   ┗ application.properties</pre><h3>Task.java</h3><p>In the dto package create the Task.java to represent our dummy data and add the lombok dependency to your classpath.</p><pre>@Data<br>@Builder<br>public class Task {<br>    private String id;<br>    private String title;<br>    private String description;<br>}</pre><h3>TaskService.java</h3><p>In the service directory add the TaskService.java and create a method to return the dummy data list.</p><pre>@Service<br>public class TaskService {<br><br>    public List&lt;Task&gt; getTasks() {<br>        List&lt;Task&gt; tasks = new ArrayList&lt;&gt;();<br>        tasks.add(Task.builder().id(&quot;1&quot;).title(&quot;Title 1&quot;).description(&quot;Description for item 1&quot;).build());<br>        tasks.add(Task.builder().id(&quot;2&quot;).title(&quot;Title 2&quot;).description(&quot;Description for item 2&quot;).build());<br>        tasks.add(Task.builder().id(&quot;3&quot;).title(&quot;Title 3&quot;).description(&quot;Description for item 3&quot;).build());<br>        return tasks;<br>    }<br>}</pre><h3>StatusController.java</h3><p>In the controller package add a REST controller to simply return a status string. We will later keep this path unprotected to test our security configuration.</p><pre>@RestController<br>public class StatusController {<br><br>    @CrossOrigin<br>    @GetMapping(path = {&quot;/api/status&quot;}, produces = MediaType.APPLICATION_JSON_VALUE)<br>    public ResponseEntity&lt;?&gt; status() {<br>        return ResponseEntity.status(HttpStatus.OK)<br>                .body(&quot;status: UP&quot;);<br>    }<br>}</pre><h3>TaskController.java</h3><p>Within the controller directory create the TaskController.java which will return the list of Tasks. We will secure this path in a next step.</p><pre>@RestController<br>@RequestMapping(value = &quot;api/&quot;)<br>@AllArgsConstructor<br>public class TaskController {<br>    TaskService taskService;<br><br>    @GetMapping(value = &quot;tasks&quot;, produces = MediaType.APPLICATION_JSON_VALUE)<br>    public ResponseEntity&lt;?&gt; getTasks() {<br>        return ResponseEntity.ok().body(<br>               taskService.getTasks());<br>    }<br>}<br>}</pre><p>At this point if you try to call your api endpoint <a href="http://localhost:8080/api/tasks">http://localhost:8080/api/tasks</a>, you should achieve a successful response including your dummy data.</p><h3>Securing your app</h3><p>Add the okta-spring-boot-starter dependency in your pom. The Okta Spring Boot Starter configures Spring Security to validate an access token attached to incoming requests from the HTTP request’s Authorization: Bearer header value.</p><pre>&lt;dependency&gt;<br>    &lt;groupId&gt;com.okta.spring&lt;/groupId&gt;<br>    &lt;artifactId&gt;okta-spring-boot-starter&lt;/artifactId&gt;<br>    &lt;version&gt;2.1.6&lt;/version&gt;<br>&lt;/dependency&gt;</pre><p>If you try to run your app you’ll get a warning indicating that you have to setup your security configuration: <em>Your security configuration must be updated before running your application in production.</em></p><p>Updating your application properties with your issuer and client_id as configured in step 1 is all you need.</p><pre>okta.oauth2.issuer= https://{yourOktaDomain}/oauth2/default<br>okta.oauth2.client-id= {yourClientId}</pre><p>Finally, we must create a web security configuration to secure all of our paths except from the “/api/status” and enable jwt token validation. Resource Server will automatically configure itself to validate JWT-encoded Bearer Tokens from your Okta issuer.</p><p>In order to be able to access our api from different origins, we’ll add some cors mapping to allow all origins and GET methods.</p><pre>@Configuration<br>@EnableWebSecurity<br>public class WebSecurityConfig {<br><br>    @Bean<br>    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {<br>        http.cors().and()<br>                .authorizeHttpRequests((requests) -&gt; requests<br>                        .requestMatchers(<br>                          new AntPathRequestMatcher(&quot;/api/status&quot;)).permitAll()<br>                        .anyRequest().authenticated())<br>                .oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt);<br>        return http.build();<br>    }<br><br>    @Bean<br>    public WebMvcConfigurer corsMappingConfigurer() {<br>        return new WebMvcConfigurer() {<br>            @Override<br>            public void addCorsMappings(CorsRegistry registry) {<br>                registry.addMapping(&quot;/**&quot;)<br>                        .allowedOrigins(&quot;*&quot;)<br>                        .allowedMethods(&quot;GET&quot;)<br>                        .allowedHeaders(&quot;*&quot;);<br>            }<br>        };<br>    }<br>}</pre><p>When running the app and performing a GET /api/tasks request, you should now get an unauthorised 401 response.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/905/1*yo9ll3IQdnIc8Ct5LheSgQ.jpeg" /><figcaption>Unauthorized request</figcaption></figure><p>Performing a GET request for /api/status should respond with a success “status: Up” string as we’ve allowed this path in our previous step. In the next part we’ll be setting up a react application to interact with our api using Okta authentication.</p><h3>3. Setup React App</h3><p>Create the react app and add required Okta dependencies. We’ll be using ant design for some basic layout styles. In this example we’ve used react 18. We’ll name our app: “client”.</p><blockquote>npx create-react-app client<br>cd client<br>npm start</blockquote><h3>Install dependencies</h3><blockquote>npm install <a href="http://twitter.com/okta/okta-auth-js">@okta/okta-auth-js</a>@latest<br>npm install <a href="http://twitter.com/okta/okta-react">@okta/okta-react</a>@latest<br>npm install react-router-dom<br>npm install antd</blockquote><h3>Create directories and files</h3><p>These are all the components we’ll need to create the demo client application. Notice that we won’t be creating any Login page. Instead we’ll be using Okta’s hosted sign in page.</p><pre>src/<br>┣ components/<br>┃ ┣ RequiredAuth.js<br>┃ ┣ Routes.js<br>┃ ┗ SideMenu.js<br>┣ okta/<br>┃ ┗ config.js<br>┣ pages/<br>┃ ┣ Dashboard.js<br>┃ ┗ Home.js<br>┣ App.css<br>┣ App.js<br>┣ index.css<br>┣ index.js<br>┗ logo.svg<br>.env.local</pre><h3>.env.local</h3><p>Start with you env.local file. Create it under your root client project directory if not present and add your variables. Variable names must have the “REACT_APP_” prefix in order for react to fetch them. Set the values for Okta ISSUER and CLIENT_ID to reflect your Okta settings as configured in step 1 along with your spring-boot server API_URL.</p><pre>REACT_APP_API_URL=http://localhost:8080/api<br>REACT_APP_ISSUER=https://{yourOktaDomain}/oauth2/default<br>REACT_APP_CLIENT_ID={yourClientId}</pre><h3>okta/config.js</h3><p>Create the config.js file under okta directory and define the oidc object which will be later used to configure okta security.</p><pre>const CLIENT_ID = process.env.REACT_APP_CLIENT_ID || &#39;{clientId}&#39;;<br>const ISSUER = process.env.REACT_APP_ISSUER || &#39;https://{yourOktaDomain}/oauth2/default&#39;;<br>const REDIRECT_URI = `${window.location.origin}/login/callback`;<br><br>export default {<br>  oidc: {<br>    clientId: CLIENT_ID,<br>    issuer: ISSUER,<br>    redirectUri: REDIRECT_URI,<br>    scopes: [&#39;openid&#39;, &#39;profile&#39;, &#39;email&#39;],<br>    pkce: true,<br>    responseType: [&#39;id_token&#39;, &#39;token&#39;]<br>  }<br>};</pre><h3>Dashboard.js</h3><p>Create the file Dashboard.js under pages. This component will be responsible for displaying the data fetched from our api. We’ll be using an antd table with two columns to display our data list. On useEffect() hook we’ll check whether the user is authenticated and if so, we’ll fetch our data from our api by passing the access token to the Authorization header.</p><pre>import React, { useState, useEffect } from &#39;react&#39;;<br>import { Table } from &quot;antd&quot;;<br>import { useOktaAuth } from &#39;@okta/okta-react&#39;;<br><br>const baseURL = process.env.REACT_APP_API_URL + &#39;/tasks&#39;;<br><br>const columns = [<br>    {<br>        title: &quot;Title&quot;,<br>        dataIndex: &quot;title&quot;,<br>    },<br>    {<br>        title: &quot;Description&quot;,<br>        dataIndex: &quot;description&quot;,<br>    }<br>]<br><br>function Dashboard() {<br><br>    const [tasks, setTasks] = useState(null);<br>    const { authState, oktaAuth } = useOktaAuth();<br><br>    useEffect(() =&gt; {<br>        if (authState &amp;&amp; authState.isAuthenticated) {<br>            const accessToken = oktaAuth.getAccessToken();<br>            fetch(`${baseURL}`, {<br>                headers: {<br>                    Authorization: `Bearer ${accessToken}`,<br>                },<br>            })<br>                .then((response) =&gt; {<br>                    return response.json();<br>                })<br>                .then((data) =&gt; {<br>                    setTasks(data);<br>                })<br>                .catch((err) =&gt; {<br>                    console.error(err);<br>                });<br>        }<br>    }, [authState, oktaAuth]);<br><br>    if (!tasks) return null;<br><br>    return (<br>        &lt;Table dataSource={tasks} columns={columns} pagination={false} rowKey=&#39;id&#39; /&gt;<br>    );<br>}<br><br>export default Dashboard;</pre><h3>Home.js</h3><p>Create the file Home.js under pages. This page will display a welcome message as long as the user is authenticated.</p><pre>import { useOktaAuth } from &#39;@okta/okta-react&#39;;<br>import React, { useState, useEffect } from &#39;react&#39;;<br>import { Spin } from &#39;antd&#39;;<br><br>function Home() {<br>  const { authState, oktaAuth } = useOktaAuth();<br>  const [userInfo, setUserInfo] = useState(null);<br><br>  useEffect(() =&gt; {<br>    if (!authState || !authState.isAuthenticated) {<br>      setUserInfo(null);<br>    } else {<br>      oktaAuth.getUser().then((info) =&gt; {<br>        setUserInfo(info);<br>      });<br>    }<br>  }, [authState, oktaAuth]);<br><br><br>  if (!authState || !userInfo) {<br>    return (<br>      &lt;Spin /&gt;<br>    );<br>  }<br><br>  return (<br>    &lt;h1&gt;<br>       Welcome {userInfo.given_name} !  &amp;#128075;<br>    &lt;/h1&gt;<br>  );<br>}<br><br>export default Home;</pre><h3>SideMenu.js</h3><p>This is an antd Menu including the required items for navigation throughout our components. For the logout process the oktaAuth.signOut() method will be called, which will redirect to Okta to end the session and then redirect back to okta hosted sign in page.</p><pre>import { Menu } from &quot;antd&quot;;<br>import { HomeOutlined, DashboardOutlined, LogoutOutlined } from &#39;@ant-design/icons&#39;<br>import { useNavigate } from &#39;react-router-dom&#39;;<br>import { useOktaAuth } from &#39;@okta/okta-react&#39;;<br><br>function SideMenu() {<br>    const navigate = useNavigate();<br>    const { oktaAuth } = useOktaAuth();<br>    const logout = async () =&gt; oktaAuth.signOut();<br><br>    return (<br>        &lt;div&gt;<br>            &lt;Menu theme=&quot;dark&quot;<br>                onClick={<br>                    ({ key }) =&gt; {<br>                        if (key != &quot;/logout&quot;) {<br>                            navigate(key);<br>                        }<br>                    }<br>                }<br>                items={[<br>                    { label: &quot;Home&quot;, key: &quot;/&quot;, icon: &lt;HomeOutlined /&gt; },<br>                    { label: &quot;Dashboard&quot;, key: &quot;/dashboard&quot;, icon: &lt;DashboardOutlined /&gt; },<br>                    { label: &quot;Logout&quot;, key: &quot;/logout&quot;, onClick: logout, icon: &lt;LogoutOutlined /&gt; }<br>                ]}&gt;<br>            &lt;/Menu&gt;<br>        &lt;/div&gt;<br>    );<br>}<br><br>export default SideMenu;</pre><h3>RequiredAuth.js</h3><p>Create the RequiredAuth.js under components. This is where our main security logic will be held. It will be used along with the Routes to display the content of each component. If the user is not authenticated, it will redirect to the okta hosted sign in page. We’ll be using the &lt;Outlet/&gt; component within the antd &lt;Content/&gt; component which will expect the content to be populated from the nested routes we’ll define in the next step.</p><pre>import React, { useEffect } from &#39;react&#39;;<br>import { useOktaAuth } from &#39;@okta/okta-react&#39;;<br>import { toRelativeUrl } from &#39;@okta/okta-auth-js&#39;;<br>import { Outlet } from &#39;react-router-dom&#39;;<br>import { Spin } from &#39;antd&#39;;<br>import { Layout } from &#39;antd&#39;;<br>import SideMenu from &#39;./SideMenu&#39;;<br><br>const { Header, Footer, Sider, Content } = Layout;<br><br>function RequiredAuth() {<br>  const { oktaAuth, authState } = useOktaAuth();<br><br>  useEffect(() =&gt; {<br>    if (!authState) {<br>      return;<br>    }<br><br>    if (!authState?.isAuthenticated) {<br>      const originalUri = toRelativeUrl(window.location.href, window.location.origin);<br>      oktaAuth.setOriginalUri(originalUri);<br>      oktaAuth.signInWithRedirect();<br>    }<br>  }, [oktaAuth, !!authState, authState?.isAuthenticated]);<br><br>  if (!authState || !authState?.isAuthenticated) {<br>    return (<br>      &lt;div style={{<br>        display: &#39;flex&#39;,<br>        alignItems: &#39;center&#39;,<br>        justifyContent: &#39;center&#39;,<br>        height: &#39;100vh&#39;,<br>      }} &gt;<br>        &lt;Spin size=&quot;large&quot; /&gt;<br>      &lt;/div&gt;<br>    );<br>  }<br><br>  return (<br>    &lt;Layout style={{ height: &quot;100vh&quot; }} &gt;<br>      &lt;Header style={{ color: &quot;white&quot; }}&gt;Header&lt;/Header&gt;<br>      &lt;Layout&gt;<br>        &lt;Sider&gt;&lt;SideMenu /&gt;&lt;/Sider&gt;<br>        &lt;Content style={{ margin: &#39;24px&#39; }}&gt;<br>          &lt;Outlet /&gt;<br>        &lt;/Content&gt;<br>      &lt;/Layout&gt;<br>      &lt;Footer&gt;Footer&lt;/Footer&gt;<br>    &lt;/Layout&gt;<br>  );<br><br>}<br><br>export default RequiredAuth;</pre><h3>Routes.js</h3><p>Create your routes file under components and set element={&lt;RequiredAuth /&gt;} on the root path. Everything under this route will require the user to be authenticated.</p><p>Notice here that we added a route for path=”login/callback” and passed the LoginCallback element for okta react sdk to handle the token exchange. This specific path should not be requiring authentication.</p><pre>import React from &#39;react&#39;;<br>import { Routes, Route, Outlet } from &#39;react-router-dom&#39;;<br>import { LoginCallback, } from &#39;@okta/okta-react&#39;;<br>import Home from &#39;../pages/Home&#39;;<br>import Dashboard from &#39;../pages/Dashboard&#39;;<br>import RequiredAuth from &#39;./RequiredAuth&#39;;<br><br>function AppRoutes() {<br>  return (<br>    &lt;Routes&gt;<br>      &lt;Route path=&quot;/&quot; element={&lt;RequiredAuth /&gt;}&gt;<br>        &lt;Route path=&#39;&#39; element={&lt;Home/&gt;} /&gt;<br>        &lt;Route path=&#39;/dashboard&#39; element={&lt;Dashboard /&gt;} /&gt;<br>        &lt;Route path=&quot;/logout&quot; /&gt;<br>      &lt;/Route&gt;<br>      &lt;Route path=&quot;login/callback&quot; element={&lt;LoginCallback /&gt;} /&gt;<br>    &lt;/Routes&gt;<br>  );<br>};<br><br>export default AppRoutes;</pre><h3>App.js</h3><p>In order for okta to secure our routes, everything should be wrapped into the Security component provided by okta-react. You need to provide the oktaAuth configuration and the restoreOriginalUri property in the &lt;Security&gt; component.</p><pre>import &#39;./App.css&#39;;<br>import React from &#39;react&#39;;<br>import { useNavigate } from &#39;react-router-dom&#39;;<br>import { OktaAuth, toRelativeUrl } from &#39;@okta/okta-auth-js&#39;;<br>import { Security } from &#39;@okta/okta-react&#39;;<br>import config from &#39;./okta/config&#39;;<br>import AppRoutes from &#39;./components/Routes&#39;;<br><br>const oktaAuth = new OktaAuth(config.oidc);<br><br>function App() {<br>  const navigate = useNavigate();<br>  const restoreOriginalUri = (_oktaAuth, originalUri) =&gt; {<br>    navigate(toRelativeUrl(originalUri || &#39;/&#39;, window.location.origin));<br>  };<br><br>  return (<br>    &lt;Security oktaAuth={oktaAuth} restoreOriginalUri={restoreOriginalUri}&gt;<br>      &lt;AppRoutes /&gt;<br>    &lt;/Security&gt;<br>  );<br>};<br><br>export default App;<br><br></pre><h3>index.js</h3><p>Finally, ensure your &lt;App/&gt; is surrounded with the &lt;BrowserRouter&gt; to enable navigation between views from different components in your React application.</p><pre>import React from &#39;react&#39;;<br>import ReactDOM from &#39;react-dom/client&#39;;<br>import &#39;./index.css&#39;;<br>import App from &#39;./App&#39;;<br>import { BrowserRouter } from &#39;react-router-dom&#39;;<br><br>const root = ReactDOM.createRoot(document.getElementById(&#39;root&#39;));<br><br>root.render(<br>    &lt;BrowserRouter&gt;<br>        &lt;App /&gt;<br>    &lt;/BrowserRouter&gt;<br>);</pre><h3>4. Running your Apps</h3><p>Run your spring server app and your client with npm start. You should be able to view your client application under localhost:3000</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/600/1*zRP7nNz2st6-XfrC3nP1_Q.gif" /><figcaption>App preview</figcaption></figure><h3>5. Summary</h3><p>The full source code can be found in GitHub here <a href="https://github.com/ramsimmin/okta-spring-boot">spring-boot-app</a> and <a href="https://github.com/ramsimmin/okta-react-client">react-app</a> .</p><p>Default access token lifetime is 1 hour. You can review this under your Okta account. From the menu select Security → API . Click on the default Authorization Server and go to the tab Access Policies, here you will find a Default Policy Rule and by clicking the edit icon, you can change the access token lifetime.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/905/1*s2TF74h-vGpwciR5W9tzKw.jpeg" /><figcaption>Okta: Default Policy Rule</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/613/1*lNfdaQjFt-h-O8Cb6ZTqJQ.jpeg" /><figcaption>Okta: Edit Policy Rule</figcaption></figure><p>While running your app you’ll be able to retrieve your Bearer token from your application local storage and use Okta’s introspect api to check the status of your token among other information.</p><pre>curl --location --request POST &#39;https://&lt;your_okta_domain&gt;/oauth2/default/v1/introspect&#39; \<br>-H &quot;Accept: application/json&quot; \<br>-H &quot;Content-Type: application/x-www-form-urlencoded&quot; \<br>-d &quot;client_id=&lt;your_client_id&gt;&quot; \<br>-d &quot;token_type_hint=access_token&quot; \<br>-d &quot;token= &lt;your_access_token_value&gt;&quot;</pre><p>If you sign out and run the above curl again, you’ll be able to see that your token is inactive.</p><pre>{<br>    &quot;active&quot;: false<br>}</pre><p>While the access token is inactive, by calling the GET /api/tasks with your Authorization Bearer header, you’ll notice that the request returns a success response. That’s because JWTs are locally validated. If you need to validate each token remotely you can use opaque tokens. There’s a great explanatory article here: <a href="https://developer.okta.com/blog/2020/08/07/spring-boot-remote-vs-local-tokens">https://developer.okta.com/blog/2020/08/07/spring-boot-remote-vs-local-tokens</a>. It fully depends on your business’ approach and your security expectations.</p><p>Thank you for reading so far! Hopefully this has helped some of you. Implementing projects using the stack described above is just a small part of our daily work for the company I work for. If the terms <em>Java</em>, <em>Spring Boot</em>, <em>Kubernetes</em>, <em>Gitlab</em>, <em>React</em> mean something to you, you may use <a href="https://apply.workable.com/persado/">this link</a> to read about our open positions, apply and join us! Alternatively, browse through <a href="https://www.persado.com/">our new website</a> 💻 to see how our technology makes a difference! 🚀</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=3f80ffc5fa6b" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>