Skip to content

Playground

The playground provides a reference implentation for the developer to inspect and exercise the User and REST API Endpoint functionality of the nuxt-saasmvp-oauth module.

Module Playground Directory Tree

./playground
├── .nuxt
├── node_modules
├── pages
│   ├── index.vue
│   ├── pageone.vue
│   ├── pagetwo.vue
│   ├── testapi.vue
│   └── testlogin.vue
├── public
├── server
│   ├── smvp.oauth.json
│   └── api
│       └── v1
│           ├── apitest.get.ts
│           ├── apitest.post.ts 
│           ├── apitest.put.ts
│           ├── apitest.patch.ts
│           ├── apitest.delete.ts
|           ├── dynamic
|           |   └── [name].get.ts
|           ├── nested
|           |   └── [name]
|           |       └── nested.get.ts
|           ├── query.get.ts
│           └── api-unprotected.get.ts 
├── app.vue
├── nuxt.config.ts
├── package-lock.json
├── package.json
└── tsconfig.json

./playground/app.vue

The app.vue file loads the Bootstrap 5 CSS and JavaScript libraries from the Bootstrap 5 Content Delivery Network (CDN); and then loads the index.vue file.

./playground/pages

index.vue

index.vue is the main page of the playground. It has a menu of items to test both User and REST API Endpoint authentication. The nuxt-saasmvp-oauth module is initialized using the client function smvpInitAuth which is called using the Nuxt onMounted life cycle hook.

pageone.vue

pageone.vue is a page protected by the definePageMeta compiler macro which invokes the smvp-pageauth named client middleware on every access to the page before allowing User navigation to pageone.vue. The User must be successfully authenticated on the testlogin.vue page before accessing any page protected by the smvp-pagauth named client middleware. Otherwise, the User is redirected to the page defined by the redirectRoute parameter. The redirectRoute parameter is initialized by the smvpInitAuth client function upon loading of the index.vue page.

pagetwo.vue

pagetwo.vue is a page protected by the definePageMeta compiler macro which invokes the smvp-pageauth named client middleware on every access to the page before allowing User navigation to pagetwo.vue. The User must be successfully authenticated on the testlogin.vue page before accessing any page protected by the smvp-pagauth named client middleware. Otherwise, the User is redirected to the page defined by the redirectRoute parameter. The redirectRoute parameter is initialized by the smvpInitAuth client function upon loading of the index.vue page.

testlogin.vue

The testlogin.vue page exercises the nuxt-saasmvp-oauth module User Authentication functionality. There are two buttons on the testlogin.vue page, Test Login and Test Logout; and a RED or GREEN indicator of the User's Login Status. The User is authenticated or logged-in when pressing the Test Login button and logged-out when pressing the Test Logout button. When the Login Status indicator is GREEN, the User has been authenticated and can successfully navigate to pageone and pagetwo. Otherwise, the User is redirected to the page defined by the redirectRoute parameter when the User tries to navigate to either pageone.vue or pagetwo.vue.

testapi.vue

The testapi.vue page exercises the nuxt-saasmvp-oauth module REST API Endpoint Authentication functionality. By first pressing the Generate API Key button, a JWT Access Token is obtained. The JWT Access Token is then used as a Bearer Token in the X-TOKEN Header of the HTTP Method request. The REST API Endpoints apitest.get.ts, apitest.post.ts, apitest.put.ts, apitest.patch.ts , and apitest.delete.ts are exercised by pressing the corresponding Test API HTTP Methods buttons GET, POST, PUT, PATCH, and DELETE. A status message to the right of each button indicates if the API defined by the HTTP Method succeeded or not. A Copy button is provided to the right of the saasmvp API Key input box that copies the JWT Access Token to the clipboard for further examination.

./playground/server

smvp.oauth.json

The nuxt-saasmvp-oauth requires a configuration file named smvp.oauth.json file in your application's ./server directory. The smvp.oauth.json file is read by the smvpServerInit.ts Authorization Server function when the nuxt-saasmvp-oauth module starts. The smvp.oauth.json file configures the nuxt-saasmvp-oauth module for both User and REST API Authentication.

The smvp.oauth.json file contains a protected json object that holds an array of strings. Each string in the protected json object specifies a REST API route that is to be authenticated by the nuxt-saasmvp-oauth module's smvp-apiauth.ts server middleware. There are two types of routes that can be protected, a strict route and a wildcard route. If a route is not included in the smvp.oauth.json file protected json object, the route is not authenticated. Don't leave out the protected json object. If no routes need to be protected, you can simply specify the protected json object with an empty array (i.e. [])

./playground/server/api/v1

apitest.get.ts (HTTP GET Method)

IETF RFC 9110 defines the HTTP GET Method as a transfer request "of a current selected representation for the target resource. A successful response reflects the quality of "sameness" identified by the target URI. Hence, retrieving identifiable information via HTTP is usually performed by making a GET request on an identifier associated with the potential for providing that information in a 200 (OK) response."

This simple protected REST API Endpoint returns a response with a HTTP status code of 200 if the string /api/v1/apitest is contained in the smvp.oauth.json file's protected object file AND the JWT Access Token is supplied in the X-TOKEN HTTP request header is authenticated by the smvp-apiauth.ts server middleware. The REST API Endpoint uses the smvpIsRestAuth server function to determine if the Endpoint has been authenticated by the smvp-apiauth.ts middleware. If the Endpoint has failed authentication, the Endpoint returns a 401 Unauthorized to the requesting client, otherwise a normal execution path is followed.

The developer is encouraged to review the NUXT 3 defineEventHandler function for additional details on creating REST API Endpoints.

ts
// apitest.get.ts
// path is /api/v1/apitest
export default defineEventHandler((event) => {
  if (!smvpIsRestAuth()) {
    event.node.res.statusCode = 401
    return {
      message: 'Unauthorized',
      status: 401,
      data: {},
    }
  }
  //
  // add GET functionality
  //
  event.node.res.statusCode = 200
  return {
    message: 'Protected',
    status: 200,
    data: { endpoint: '/api/v1/apitest', method: 'GET' },
  }
})

apitest.post.ts (HTTP POST Method)

IETF RFC 9110 defines the HTTP POST Method as a request "that the target resource process the representation enclosed in the request according to the resource's own specific semantics. For example, POST is used for the following functions (among others):

  1. Providing a block of data, such as the fields entered into an HTML form, to a data-handling process;
  2. Posting a message to a bulletin board, newsgroup, mailing list, blog, or similar group of articles;
  3. Creating a new resource that has yet to be identified by the origin server; and
  4. Appending data to a resource's existing representation(s)".

This simple protected REST API Endpoint returns a response with a HTTP status code of 200 if the string /api/v1/apitest is contained in the smvp.oauth.json file's protected object file AND the JWT Access Token is supplied in the X-TOKEN HTTP request header is authenticated by the smvp-apiauth.ts server middleware. The REST API Endpoint uses the smvpIsRestAuth server function to determine if the Endpoint has been authenticated by the smvp-apiauth.ts middleware. If the Endpoint has failed authentication, the Endpoint returns a 401 Unauthorized to the requesting client, otherwise a normal execution path is followed.

The developer is encouraged to review the NUXT 3 defineEventHandler function for additional details on creating REST API Endpoints.

ts
// apitest.post.ts
// path is /api/v1/apitest
export default defineEventHandler(async (event) => {
  if (!smvpIsRestAuth()) {
    event.node.res.statusCode = 401
    return {
      message: 'Unauthorized',
      status: 401,
      data: {},
    }
  }
  const body = await readBody(event)
  console.log(body)
  //
  // add POST functionality
  //
  event.node.res.statusCode = 200
  return {
    message: 'Protected',
    status: 200,
    data: { body },
  }
})

apitest.put.ts (HTTP PUT Method)

IETF RFC 9110 specifies that the HTTP PUT Method "requests that the state of the target resource be created or replaced with the state defined by the representation enclosed in the request message content. A successful PUT of a given representation would suggest that a subsequent GET on that same target resource will result in an equivalent representation being sent in a 200 (OK) response. However, there is no guarantee that such a state change will be observable, since the target resource might be acted upon by other user agents in parallel, or might be subject to dynamic processing by the origin server, before any subsequent GET is received. A successful response only implies that the user agent's intent was achieved at the time of its processing by the origin server".

This simple protected REST API Endpoint returns a response with a HTTP status code of 200 if the string /api/v1/apitest is contained in the smvp.oauth.json file's protected object file AND the JWT Access Token is supplied in the X-TOKEN HTTP request header is authenticated by the smvp-apiauth.ts server middleware. The REST API Endpoint uses the smvpIsRestAuth server function to determine if the Endpoint has been authenticated by the smvp-apiauth.ts middleware. If the Endpoint has failed authentication, the Endpoint returns a 401 Unauthorized to the requesting client, otherwise a normal execution path is followed.

The developer is encouraged to review the NUXT 3 defineEventHandler function for additional details on creating REST API Endpoints.

ts
// apitest.put.ts
// path is /api/v1/apitest
export default defineEventHandler(async (event) => {
  if (!smvpIsRestAuth()) {
    event.node.res.statusCode = 401
    return {
      message: 'Unauthorized',
      status: 401,
      data: {},
    }
  }
  const body = await readBody(event)
  console.log(body)
  //
  // add PUT functionality
  //
  event.node.res.statusCode = 200
  return {
    message: 'Protected',
    status: 200,
    data: { body },
  }
})

apitest.patch.ts (HTTP PATCH Method)

IETF RFC 5789 comments that "several applications extending the Hypertext Transfer Protocol (HTTP) require a feature to do partial resource modification. The existing HTTP PUT method only allows a complete replacement of a document. This proposal adds a new HTTP method, PATCH, to modify an existing HTTP resource".

RFC 5789 goes on further to state that "the PATCH method requests that a set of changes described in the request entity be applied to the resource identified by the Request-URI. The set of changes is represented in a format called a "patch document" identified by a media type. If the Request-URI does not point to an existing resource, the server MAY create a new resource, depending on the patch document type (whether it can logically modify a null resource) and permissions, etc.

This simple protected REST API Endpoint returns a response with a HTTP status code of 200 if the string /api/v1/apitest is contained in the smvp.oauth.json file's protected object file AND the JWT Access Token is supplied in the X-TOKEN HTTP request header is authenticated by the smvp-apiauth.ts server middleware. The REST API Endpoint uses the smvpIsRestAuth server function to determine if the Endpoint has been authenticated by the smvp-apiauth.ts middleware. If the Endpoint has failed authentication, the Endpoint returns a 401 Unauthorized to the requesting client, otherwise a normal execution path is followed.

The developer is encouraged to review the NUXT 3 defineEventHandler function for additional details on creating REST API Endpoints.

ts
// apitest.patch.ts
// path is /api/v1/apitest
export default defineEventHandler(async (event) => {
  if (!smvpIsRestAuth()) {
    event.node.res.statusCode = 401
    return {
      message: 'Unauthorized',
      status: 401,
      data: {},
    }
  }
  const body = await readBody(event)
  console.log(body)
  //
  // add PATCH functionality
  //
  event.node.res.statusCode = 200
  return {
    message: 'Protected',
    status: 200,
    data: { body },
  }
})

apitest.delete.ts (HTTP DELETE Method)

IETF RFC 9110 defines the HTTP DELETE Method as a request "that the origin server remove the association between the target resource and its current functionality. In effect, this method is similar to the rm command in UNIX: it expresses a deletion operation on the URI mapping of the origin server rather than an expectation that the previously associated information be deleted".

This simple protected REST API Endpoint returns a response with a HTTP status code of 200 if the string /api/v1/apitest is contained in the smvp.oauth.json file's protected object file AND the JWT Access Token is supplied in the X-TOKEN HTTP request header is authenticated by the smvp-apiauth.ts server middleware. The REST API Endpoint uses the smvpIsRestAuth server function to determine if the Endpoint has been authenticated by the smvp-apiauth.ts middleware. If the Endpoint has failed authentication, the Endpoint returns a 401 Unauthorized to the requesting client, otherwise a normal execution path is followed.

The developer is encouraged to review the NUXT 3 defineEventHandler function for additional details on creating REST API Endpoints.

ts
// apitest.delete.ts
// path is /api/v1/apitest
export default defineEventHandler(async (event) => {
  if (!smvpIsRestAuth()) {
    event.node.res.statusCode = 401
    return {
      message: 'Unauthorized',
      status: 401,
      data: {},
    }
  }
  const body = await readBody(event)
  console.log(body)
  //
  // add DELETE functionality
  //
  event.node.res.statusCode = 200
  return {
    message: 'Protected',
    status: 200,
    data: { body },
  }
})

dynamic/[name].get.ts

This simple protected REST API Endpoint /api/v1/dynamic/[name].get.ts uses dynamic parameters within brackets. The Endpoint returns a response with a HTTP status code of 200 if the string /api/v1/dynamic/* is contained in the smvp.oauth.json file's protected object file AND the JWT Access Token is supplied in the X-TOKEN HTTP request header is authenticated by the smvp-apiauth.ts server middleware. The REST API Endpoint uses the smvpIsRestAuth server function to determine if the Endpoint has been authenticated by the smvp-apiauth.ts middleware. If the Endpoint has failed authentication, the Endpoint returns a 401 Unauthorized to the requesting client, otherwise a normal execution path is followed.

The developer is encouraged to review the NUXT 3 Route Parameters section for additional details on creating REST API Endpoints using dynamic parameters.

ts
// dynamic/[name].get.ts
// path is api/v1/dynamic/[name].get.ts
export default defineEventHandler((event) => {
  if (!smvpIsRestAuth()) {
    event.node.res.statusCode = 401
    return {
      message: 'Unauthorized',
      status: 401,
      data: {},
    }
  }
  const name = getRouterParam(event, 'name')
  const result = `Hello, ${name}`
  //
  // add funtionality here
  //
  event.node.res.statusCode = 200
  return {
    message: 'Protected',
    status: 200,
    data: { result },
  }
})

nested/[name]/nested.get.ts

Nested Endpoints allows the designer to logically organize a group of related Endpoints using dynamic parameters. This simple protected REST API Endpoint api/v1/nested/[name]/nested.get.ts uses dynamic parameters within brackets. The Endpoint returns a response with a HTTP status code of 200 if the string "/api/v1/nested/* is contained in the smvp.oauth.json file's protected object file AND the JWT Access Token is supplied in the X-TOKEN HTTP request header is authenticated by the smvp-apiauth.ts server middleware. The REST API Endpoint uses the smvpIsRestAuth server function to determine if the Endpoint has been authenticated by the smvp-apiauth.ts middleware. If the Endpoint has failed authentication, the Endpoint returns a 401 Unauthorized to the requesting client, otherwise a normal execution path is followed.

The developer is encouraged to review the NUXT 3 Route Parameters section for additional details on creating REST API Endpoints using dynamic parameters.

ts
// api/v1/nested/[name]/nested.get.ts
// path is api/v1/nested/[name]/nested
export default defineEventHandler((event) => {
  if (!smvpIsRestAuth()) {
    event.node.res.statusCode = 401
    return {
      message: 'Unauthorized',
      status: 401,
      data: {},
    }
  }
  const name = getRouterParam(event, 'name')
  const result = `Hello, ${name} /nested`
  //
  // add functionality here
  //
  event.node.res.statusCode = 200
  return {
    message: 'Protected',
    status: 200,
    data: { result },
  }
})

query.get.ts

This simple protected REST API Endpoint /api/v1/dynamic/[name].get.ts uses query parameters. The Endpoint returns a response with a HTTP status code of 200 if the string /api/v1/query/* is contained in the smvp.oauth.json file's protected object file AND the JWT Access Token is supplied in the X-TOKEN HTTP request header is authenticated by the smvp-apiauth.ts server middleware. The REST API Endpoint uses the smvpIsRestAuth server function to determine if the Endpoint has been authenticated by the smvp-apiauth.ts middleware. If the Endpoint has failed authentication, the Endpoint returns a 401 Unauthorized to the requesting client, otherwise a normal execution path is followed.

The developer is encouraged to review the NUXT 3 Query Parameters section for additional details on creating REST API Endpoints using query parameters.

ts
// query.get.ts
// path is api/v1/query?lastName=name&age=age
export default defineEventHandler((event) => {
  if (!smvpIsRestAuth()) {
    event.node.res.statusCode = 401
    return {
      message: 'Unauthorized',
      status: 401,
      data: {},
    }
  }
  const result = getQuery(event)
  //
  // add functionality here
  //
  event.node.res.statusCode = 200
  return {
    message: 'Protected',
    status: 200,
    data: { result },
  }
})

api-unprotected.get.ts (Simple HTTP GET request Example)

This simple example illustrates the construction of a unprotected REST API Endpoint that does not require authentication. Notice the absence of the smvpIsRestAuth function and the corresponding authentication guard logic shown in the previous examples.

ts
// api-unprotected.get.ts
// path is /api/v1/api-unprotected
export default defineEventHandler((event) => {
  // add functionality here
  event.node.res.statusCode = 200
  return {
    message: 'Unprotected',
    status: 200,
    data: { },
  }
})

Navigate to the unprotected REST API Endpoint in the browser using a GET request

sh
http://localhost:3000/api/v1/api-unprotected

HTTP Response

The result of navigating to /api/v1/api-unprotected returns an HTTP status of 200 with the following response:

json
{
  "message": "Unprotected",
  "status": 200,
  "data": {}
}

Exercising the Playground

When the smvpInitAuth parameter logFlag is TRUE and the smvp.oauth.json file's oauth.logFlag field is TRUE, the developer can observe both the client and server console logs in real-time to assist in the creation and debugging of User authentication and developer defined REST API Endpoints.

Initialization

Client and Server Logs (Normal Processing)

1. Start the playground by running the command `npm run dev` from a console. Notice the following log entry:
[Server Log] 2024-05-22T22:16:33.927Z saasmvp OAUTH smvpServerInit.ts: INITIALIZED
[Client Log] Wed May 22 2024 17:32:04 GMT-0500 (Central Daylight Time) saasmvp OAUTH smvpInitAuth.ts client INITIALIZED

User Authentication

Client and Server Logs (Normal Processing)

1. Clicking on the `Test Login` menu link on the `index.vue` page navigates to the `testlogin` page and shows the following:
[Server Log] 2024-05-22T22:35:22.292Z saasmvp OAUTH smvp-cors.ts server middleware ORIGIN: http://localhost:3000
[Server Log] 2024-05-22T22:35:22.295Z saasmvp OAUTH smvp-apiauth.ts server middleware: ROUTE: /favicon.ico *** UNPROTECTED ***

2. Pressing the `Test Login` button authenticates the User and changes the 'Login Status' indicator from RED to GREEN. Observe the following log entries:
[Server Log] 2024-05-22T22:36:43.890Z saasmvp OAUTH smvp-cors.ts server middleware ORIGIN: http://localhost:3000
[Server Log] 2024-05-22T22:36:43.892Z saasmvp OAUTH smvp-apiauth.ts server middleware: ROUTE: /api/smvp/smvp-user-token *** UNPROTECTED ***
[Server Log] 2024-05-22T22:36:43.901Z saasmvp OAUTH user-token.post.ts: JWT Token Generated NOW: 1716417403
[Server Log] 2024-05-22T22:36:43.920Z saasmvp OAUTH smvp-cors.ts server middleware ORIGIN: http://localhost:3000
[Server Log]2024-05-22T22:36:43.922Z saasmvp OAUTH smvp-apiauth.ts server middleware: ROUTE: /api/smvp/smvp-authorize *** UNPROTECTED ***
[Server Log] 2024-05-22T22:36:43.931Z saasmvp OAUTH smvp-authorize.posts.ts: JWT Token Authorized NOW: 1716417403 EXPIRES: 1716424603

3. Clicking the `Page One` link on the `testlogin` page shows the following:
[Server Log] 2024-05-22T22:39:00.096Z saasmvp OAUTH smvp-cors.ts server middleware ORIGIN: http://localhost:3000
[Server Log] 2024-05-22T22:39:00.097Z saasmvp OAUTH smvp-apiauth.ts server middleware: ROUTE: /api/smvp/smvp-authorize *** UNPROTECTED ***
[Server Log] 2024-05-22T22:39:00.100Z saasmvp OAUTH smvp-authorize.posts.ts: JWT Token Authorized NOW: 1716417540 EXPIRES: 1716424603
[Server Log] 2024-05-22T22:39:00.189Z saasmvp OAUTH smvp-cors.ts server middleware ORIGIN: http://localhost:3000
[Server Log] 2024-05-22T22:39:00.192Z saasmvp OAUTH smvp-apiauth.ts server middleware: ROUTE: /favicon.ico *** UNPROTECTED ***
[Client Log] Wed May 22 2024 17:39:00 GMT-0500 (Central Daylight Time) 'saasmvp OAUTH smvp-pageauth.ts client middleware: ROUTE:' '/pageone' '*** AUTHORIZED ***'

4. Clicking on the `Page Two` link on the `pageone` page reveals the following:
[Server Log] 2024-05-22T22:41:59.889Z saasmvp OAUTH smvp-cors.ts server middleware ORIGIN: http://localhost:3000
[Server Log] 2024-05-22T22:41:59.891Z saasmvp OAUTH smvp-apiauth.ts server middleware: ROUTE: /api/smvp/smvp-authorize *** UNPROTECTED ***
[Server Log] 2024-05-22T22:41:59.894Z saasmvp OAUTH smvp-authorize.posts.ts: JWT Token Authorized NOW: 1716417719 EXPIRES: 1716424603
[Server Log] 2024-05-22T22:41:59.980Z saasmvp OAUTH smvp-cors.ts server middleware ORIGIN: http://localhost:3000
[Server Log] 2024-05-22T22:41:59.982Z saasmvp OAUTH smvp-apiauth.ts server middleware: ROUTE: /favicon.ico *** UNPROTECTED ***
[Client Log] Wed May 22 2024 17:41:59 GMT-0500 (Central Daylight Time) 'saasmvp OAUTH smvp-pageauth.ts client middleware: ROUTE:' '/pagetwo' '*** AUTHORIZED ***'

5. Navigate back to the `testlogin` page from `pagetwo` by clicking on the `Test Login` link. Notice the following:
[Server Log] 2024-05-22T22:43:45.637Z saasmvp OAUTH smvp-cors.ts server middleware ORIGIN: http://localhost:3000
[Server Log] 2024-05-22T22:43:45.639Z saasmvp OAUTH smvp-apiauth.ts server middleware: ROUTE: /api/smvp/smvp-authorize *** UNPROTECTED ***
[Server Log] 2024-05-22T22:43:45.644Z saasmvp OAUTH smvp-authorize.posts.ts: JWT Token Authorized NOW: 1716417825 EXPIRES: 1716424603
[Server Log] 2024-05-22T22:43:45.655Z saasmvp OAUTH smvp-cors.ts server middleware ORIGIN: http://localhost:3000
[Server Log] 2024-05-22T22:43:45.659Z saasmvp OAUTH smvp-apiauth.ts server middleware: ROUTE: /favicon.ico *** UNPROTECTED ***

6. Press the `Test Logout` button on the `testlogin` page. The 'Login Status' indicator turns from GREEN to RED. Observe the following:
[Client Log] Wed May 22 2024 17:45:00 GMT-0500 (Central Daylight Time) 'saasmvp OAUTH smvpLogout.ts STATUS: Logout SUCCESSFUL'

7. From the 'testlogin' page navigate to `pageone` by clicking on the `Page One` link. Observe that the navigation does not succeed and is redirected back to the `testlogin` page.
[Client Log] Wed May 22 2024 17:45:51 GMT-0500 (Central Daylight Time) 'saasmvp OAUTH smvp-pageauth.ts client middleware: ROUTE:' '/pageone' '*** UNAUTHORIZED ***'

8. From the 'testlogin' page navigate to `pagetwo` by clicking on the `Page Two` link. Observe that the navigation does not succeed and is redirected back to the `testlogin` page.
[Client Log] Wed May 22 2024 17:46:11 GMT-0500 (Central Daylight Time) 'saasmvp OAUTH smvp-pageauth.ts client middleware: ROUTE:' '/pagetwo' '*** UNAUTHORIZED ***'

9. Observe that navigating to an unprotected page by clicking on the `Home` or `Test API` menu item that navigation to those pages proceeds without interruption.

REST API Endpoint Authentication

Client and Server Logs (Normal Processing)

1. Clicking on the `Test API` menu link on the `index.vue` page navigates to the `testapi` page and shows the following:
[Server Log] 2024-05-22T22:49:13.719Z saasmvp OAUTH smvp-cors.ts server middleware ORIGIN: http://localhost:3000
[Server Log] 2024-05-22T22:49:13.720Z saasmvp OAUTH smvp-apiauth.ts server middleware: ROUTE: /favicon.ico *** UNPROTECTED ***

2. Pressing the `Generate API Key` on the `testapi` page requests a JWT Access Token (i.e. Bearer Token). The log indicates that:
[Server Log] 2024-05-22T22:49:59.162Z saasmvp OAUTH smvp-cors.ts server middleware ORIGIN: http://localhost:3000
[Server Log] 2024-05-22T22:49:59.164Z saasmvp OAUTH smvp-apiauth.ts server middleware: ROUTE: /api/smvp/smvp-api-token *** UNPROTECTED ***

3. Test any of the API HTTP Methods by pressing the `GET`, `POST`, `PUT`, `PATCH`, `DELETE`, Dynamic, Nested, or Query buttons. The JWT Access Token just created will be used as the Bearer Token in the X-TOKEN HTTP Header as part of the REST API Endpoint request. Notice that the status message to the right of the button pressed changes from the Method name (i.e. get) to `Protected`. Observe the following:
[Server Log] 2024-05-22T22:53:00.713Z saasmvp OAUTH smvp-cors.ts server middleware ORIGIN: http://localhost:3000
[Server Log] 2024-05-22T22:53:00.714Z saasmvp OAUTH smvp-apiauth.ts server middleware: ROUTE: /api/v1/apitest *** PROTECTED ***
[Server Log] 2024-05-22T22:53:00.718Z saasmvp OAUTH smvp-apiauth.ts server middleware: API Endpoint Authenticated NOW: 1716418380 EXPIRES: 2031994199

4. Next, mutilate the generated API key shown on the `testapi` page `saasmvp API Key` input box. by modifying the key through character deletion, substitution or addition. Now, test any of the API HTTP Methods by pressing the `GET`, `POST`, `PUT`, `PATCH` or `DELETE` buttons. Notice that the status message to the right of the button pressed changes from the Method name (i.e. get) to `Unauthorized`. Observe the following log entries:
[Server Log] 2024-05-22T22:54:40.419Z saasmvp OAUTH smvp-cors.ts server middleware ORIGIN: http://localhost:3000
[Server Log] 2024-05-22T22:54:40.420Z saasmvp OAUTH smvp-apiauth.ts server middleware: ROUTE: /api/v1/apitest *** PROTECTED ***
[Server Log] 2024-05-22T22:54:40.421Z saasmvp OAUTH smvp-apiauth.ts server middleware: API Endpoint Authentication ERROR: TOKEN MALFORMED OR EXPIRED

5. Press the 'Generate API Key' on the `testapi` page and repeat steps 3-4 if desired

Released under the MIT License