Skip to content

REST API Endpoint Authentication

The nuxt-saasmvp-oauth module can be used for either or both User and REST API Endpoint authentication. REST API Endpoint authentication is implemented using client functions, server middleware and associated Authorization Server REST API endpoints.

READ THIS FIRST

Be sure to review the steps required to initialize the nuxt-saasmvp-oauth module before proceeding.

Client Functions

smvpGetOAuthApiKey

Thenuxt-saasmvp-oauth module provides the smvpGetOAuthApiKey client function that sends an Implicit Authorization Grant to the Authorization Server REST API Endpoint smvp-api-token.post.ts. The smvp-api-token.post.ts REST API Endpoint returns a JWT Access Token and Status code to smvpGetOAuthApiKey in a JSON object. If a JWT Access Token has been successfully generated by the Authorization Server, the JWT Access Token will be returned to smvpGetOAuthApiKey with the HTTP status code 200, otherwise the JWT Access Token returned will be NULL and the HTTP status code 400. The lifetime of the JWT Access Token is hardcoded to be valid for ten years and is attached to the Authorization Grant claim acctNum:string The JWT Access Token can be used as a Bearer Token in the authentication of Developer defined REST API Endpoints.

Type

ts
smvpGetOAuthApiKey(acctNum:string):Promise<string>

Parameters

Parameter: acctNum
 
Type: String Array, required
 
Description: The acctNum claim for the Implicit Authorization Grant. Binds an Account Number or other unique identifier to the JWT Access Token for use as a Bearer Token in a Developer defined REST API Endpoint.

Examples

ts
<script setup>
const apiKey = ref();

const genApiKey = async () => {
  const acctNum = "1111";
  apiKey.value = await smvpGetOAuthApiKey(acctNum);
};
</script>

Server Functions

smvpIsRestAuth

The smvpIsRestAuth Server function returns TRUE if the developer defined API REST Endpoint JWT Access Token (Bearer Token) has been authenticated by the smvp-apiauth.ts middlewware, otherwise FALSE if token is invalid.

Type

ts
smvpIsRestAuth(void):boolean

Parameters

None

Examples

TIP

Use the following template when writing your REST API Server Endpoints

ts
export default defineEventHandler((event) => {
  if (!smvpIsRestAuth()) {
    event.node.res.statusCode = 401
    return {
      message: 'Unauthorized',
      status: 401,
      data: {},
    }
  }

  //
  // Developer REST API Endpoint code goes here
  //

  //normal return example
  event.node.res.statusCode = 200
    return {
      message: 'Success',
      status: 200,
      data: {}
    }
})

Developer Defined REST API Endpoints

When defining your own REST API Endpoints, you can refer both to the nuxt-saasmvp-oauth module playground for a reference implementation and the official NUXT 3 Server REST API Examples. You may also want to refer to the Stack Overflow blog post entitled Best Practices for REST API Design.

X-TOKEN Header

The JWT Access Token (i.e. Bearer Token) must be in the X-TOKEN HTTP(S) Header which is subsequently authenticated by the smvp-apiauth.ts server middleware BEFORE the developer defined REST API Endpoint is reached. The REST API Endpoint will use the smvpIsRestAuth server function to determine if the request will be honored by the REST API Endpoint or a 401 Unauthorized HTTP status will be sent back to the requestor. When calling your REST API Endpoints from the client, refer to the following examples:

GET HTTP Method Client Example

In the GET HTTP method example, there is no body sent in the HTTP(S) request to the developer defined REST API Endpoint. While there are several libraries available to help the developer with messaging REST API Endpoints, this example uses the JavaScript fetch API.

ts
const getMethod = async (jwtToken:string) => {
  try {
    const response = await fetch("/api/v1/apitest", 
    { method: "GET",
      headers : {
      "Content-Type": "application/json",
      "X-TOKEN": jwtToken,
      },
    })

    const json = await response.json();
    console.log(json) 
    //any further processing

  } catch (error) {
    console.log(error);
    //process error
  }//end of try-catch block

  //any further processing
};

POST, PUT, PATCH, DELETE HTTP Method Client Example

In the POST, PUT, PATCH, and DELETE HTTP method example, a body is sent in the HTTP(S) request to the developer defined REST API Endpoint. While there are several libraries available to help the developer with messaging REST API Endpoints, this example uses the JavaScript fetch API.

ts
const otherMethods = async (jwtToken:string) => {
  const jsonBody = {"string": "text", "number": 1}  //any json object
  const body = Object.assign({}, jsonBody);

  try {
    const response = await fetch("/api/v1/apitest", 
    { method: "POST", // or 'PUT' or 'PATCH' or 'DELETE'
      headers : {
      "Content-Type": "application/json",
      "X-TOKEN": jwtToken,
      },
      body: JSON.stringify(body),
    })

    const json = await response.json();
    console.log(json) 
    //any further processing

  } catch (error) {
    console.log(error);
    //process error
  }//end of try-catch block

  //any further processing
};

Server Middleware

smvp-apiauth.ts

The nuxt-saasmvp-oauth module uses the smvp-apiauth.ts server middleware which is installed when Nuxt loads the nuxt-saasmvp-oauth module. The smvp-apiauth.ts server middleware handler will run on every HTTP request before any other server route to determine if the developer defined REST API Endpoint is protected and needs to be authenticated using the JWT Access Token (i.e. Bearer Token) provided in the REST API Endpoint X-TOKEN header of the HTTP request.

Defining Protected REST API Routes

The nuxt-saasmvp-oauth module expects developer defined REST API Endpoints to adhere to the following directory tree structure inside of the NUXT 3 application. NUXT 3 expects that all APIs will be located in the ./server/api directory. The nuxt-saasmvp-oauth module goes a step further by enforcing a version directory ./server/api/v1, ./server/api/v2 ... ./server/api/v99 in order to provide a best practice for versioning REST APIs and more importantly for determing if a REST API route should be protected by the nuxt-saasmvp-oauth server middleware.

The most important step in configuring the nuxt-saasmvp-oauth module's Authorization Server is to make sure you provide a 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.

REST API Directory Tree Structure

txt
.
├── server
│   │   ├── smvp.oauth.json
│   ├── api
│   │   ├── v1
│   │   │   ├── api.get.ts
│   │   │   ├── api.post.ts
│   │   │   ├── api.put.ts
│   │   │   ├── api.patch.ts
│   │   │   ├── api.delete.ts
│   │   └── v99
│   │       ├── api.get.ts
│   │       ├── api.post.ts
│   │       ├── api.put.ts
│   │       ├── api.patch.ts
│   │       └── api.delete.ts

The smvp.oauth.json protected object

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. [])

TIP

The nuxt-saasmvp-oauth module playground has examples of both static and wildcard REST API Endpoints for your review.

Strict Routes

A strict route requires an exact match of the REST API route path name for developer REST API Endpoint authentication to succeed. An example of a strict route looks like /api/v1/apitest.

Wildcard Routes

A wildcard route allows for a REST API route path name to contain a variable number of additional nested paths, dynamic parameters or query parameters that need to be supplied to a developer defined REST API Endpoint. A wildcard on a protected json object appends /* to a static route. An example of a wildcard route appears as /api/v1/apitest/*.

Dynamic Parameter with Nested Path REST API Example

The developer defined nested path REST API /api/v1/apitest/[id]/balance Endpoint passes validation when specifying a protected json object entry of /api/vi/apitest/*. If a strict entry of /api/v1/apitest is used, the smvp-apiauth.ts server middleware will fail validation and FALSE will be returned when calling the smvpServerRestAuth function in the developer defined REST API Endpoint. See Nuxt Route Parameters for more information on the use of dynamic parameters in REST API Endpoints.

Query Parameter REST API Example

The developer defined query parameter REST API /api/v1/apitest?lastname=Smith&age=30 Endpoint passes validation when specifying a protected json object entry of /api/vi/apitest/*. If a strict entry of /api/v1/apitest is used, the smvp-apiauth.ts server middleware will fail validation and FALSE will be returned when calling the smvpServerRestAuth function in the developer defined REST API Endpoint. See Nuxt Query Parameters for more information on the use of query parameters in REST API Endpoints.

Authorization Server REST API

The nuxt-saasmvp-oauth module contains an Authorization Server that has an additional REST API Endpoint, smvp-api-token.post.ts which is used to issue JWT Access Tokens for use in a Developer defined REST API Endpoint.

smvp-api-token.post.ts

The nuxt-saasmvp-oauth module smvpGetOAuthApiKey client function sends an Implicit Authentication Grant request to the Authorization Server smvp-api-token.post.ts REST API Endpoint to get a JWT Access Token. The Developer should never message this REST API Endpoint directly and is shown for educational purposes only.

JSON Implicit Authorization Grant Request

json
{ 
  "iss": "saasmvp", 
  "sub": "api-token", 
  "jti": null, 
  "acctno": "1111", 
  "ts": 1704414495
}

Parameters

Parameter: iss
 
Type: String, required, read-only
 
Description: JWT issuer claim. Hardcoded by the `smvpGetOAuthApiKey` client function.

Parameter: sub
 
Type: String, required, read-only
 
Description: JWT subject claim. Hardcoded by the `smvpGetOAuthApiKey` client function.

Parameter: jti
 
Type: String, required, read-only
 
Description: JWT ID. Reserved for future use. Hardcoded by the `smvpGetOAuthApiKey` client function.

Parameter: acctNum
 
Type: String, required
 
Description: The acctNum claim for the Implicit Authorization Grant. Binds an Account Number or other unique identifier to the JWT Access Token. A parameter supplied to the `smvpGetOAuthApiKey` client function by the Developer.

Parameter: ts
 
Type: Number, required
 
Description: The current Unix Epoch time for the Implicit Authorization Grant. Hardcoded by the smvpGetOAuthApiKey` client function.

cURL Example

sh
curl --location 'http://localhost:3000/api/smvp/smvp-api-token' \
--header 'Content-Type: application/json' \
--data '{ 
  "iss": "saasmvp", 
  "sub": "api-token", 
  "jti": null, 
  "acctno": "1111", 
  "ts": 1704414495
}'

Valid JSON Response

json
{
  "message": "JWT API Token Generated",
  "status": 200,
  "data": {
    "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzYWFzbXZwIiwic3ViIjoiYXBpLXRva2VuIiwianRpIjpudWxsLCJhY2N0bm8iOiIxMTExIiwidHMiOjE3MTYzMzk3MzQsImlhdCI6MTcxNjMzOTczNCwiZXhwIjoyMDMxOTE1NzM0fQ.jb8aTP92UQSV4-LukKCOf06PTXC5DMcWXG2t50vZLZk"
  }
}

Error JSON Response

json
{
  "message": "JWT API Token Not Generated",
  "status": 400,
  "data": {
    "token": null
  }
}

Released under the MIT License