---
title: Protecting API routes
description: Protect API routes by enforcing 2FA using session claim validators in various programming languages.
sidebar:
  hidden: true
  order: 3
---

In the previous steps, we saw the a session is created after the first factor, with `SecondFactorClaim` set to false, and then after the second factor is completed, we update that value to true.

## 1. Protecting all APIs

We want to protect all the application APIs such that they are accessible only when `SecondFactorClaim` is `true` - indicating that the user has completed 2FA. We can do this by by overriding the `getGlobalClaimValidators` function in the Session recipe.

<CodeGroup group="backend-language">
<Tab title="Node.js" value="nodejs">
```tsx check=false reason="example uses the application-defined SecondFactorClaim from the preceding setup"
import Session from "supertokens-node/recipe/session";

Session.init({
  override: {
    functions: (oI) => {
      return {
        ...oI,
        getGlobalClaimValidators: (input) => [
          ...input.claimValidatorsAddedByOtherRecipes,
          SecondFactorClaim.validators.hasValue(true),
        ],
      };
    },
  },
});
```
</Tab>
<Tab title="Go" value="go">
```go
import (
	"github.com/supertokens/supertokens-golang/recipe/session"
	"github.com/supertokens/supertokens-golang/recipe/session/claims"
	"github.com/supertokens/supertokens-golang/recipe/session/sessmodels"
	"github.com/supertokens/supertokens-golang/supertokens"
)

func main() {

	_, SecondFactorClaimValidator := claims.BooleanClaim("2fa-completed", func(userId, tenantId string, userContext supertokens.UserContext) (interface{}, error) {
		return false, nil
	}, nil)

	session.Init(&sessmodels.TypeInput{
		Override: &sessmodels.OverrideStruct{
			Functions: func(originalImplementation sessmodels.RecipeInterface) sessmodels.RecipeInterface {
                
				(*originalImplementation.GetGlobalClaimValidators) = func(userId string, claimValidatorsAddedByOtherRecipes []claims.SessionClaimValidator, tenantId string, userContext supertokens.UserContext) ([]claims.SessionClaimValidator, error) {
					claimValidatorsAddedByOtherRecipes = append(claimValidatorsAddedByOtherRecipes,
						SecondFactorClaimValidator.HasValue(true, nil, nil))
					return claimValidatorsAddedByOtherRecipes, nil
				}

				return originalImplementation
			},
		},
	})
}
```
</Tab>
<Tab title="Python" value="python">
```python
from typing import List, Dict, Any
from supertokens_python.recipe.session.claims import BooleanClaim
from supertokens_python.recipe import session
from supertokens_python.recipe.session.interfaces import (
    RecipeInterface,
    SessionClaimValidator,
)
from supertokens_python.types import RecipeUserId

SecondFactorClaim = BooleanClaim(
    key="2fa-completed", fetch_value=lambda _, __, ___, ____, _____: False
)


def override_session_functions(original_implementation: RecipeInterface):

    async def get_global_claim_validators(
        tenant_id: str,
        user_id: str,
        recipe_user_id: RecipeUserId,
        claim_validators_added_by_other_recipes: List[SessionClaimValidator],
        user_context: Dict[str, Any],
    ):
        return claim_validators_added_by_other_recipes + [
            SecondFactorClaim.validators.has_value(True)
        ]


    original_implementation.get_global_claim_validators = get_global_claim_validators
    return original_implementation


session.init(
    override=session.InputOverrideConfig(functions=override_session_functions)
)
```
</Tab>
</CodeGroup>

## 2. Protecting specific API routes

If instead, you want to enforce 2FA on certain API routes, you can add the validator only when calling the `verifySession` function:

<CodeGroup group="backend-language">
<Tab title="Node.js" value="nodejs">
```tsx check=false reason="example uses the application-defined SecondFactorClaim from the preceding setup"
import express from "express";
import { verifySession } from "supertokens-node/recipe/session/framework/express";
import { SessionRequest } from "supertokens-node/framework/express";

let app = express();

app.post(
  "/like-comment",
  verifySession({
    overrideGlobalClaimValidators: (globalValidators) => [
      ...globalValidators,
      SecondFactorClaim.validators.hasValue(true),
    ],
  }),
  (req: SessionRequest, res) => {
    //....
  },
);
```
</Tab>
<Tab title="Go" value="go">
```go
import (
	"net/http"

	"github.com/supertokens/supertokens-golang/recipe/session"
	"github.com/supertokens/supertokens-golang/recipe/session/claims"
	"github.com/supertokens/supertokens-golang/recipe/session/sessmodels"
	"github.com/supertokens/supertokens-golang/supertokens"
)

func main() {
	_, SecondFactorClaimValidator := claims.BooleanClaim("2fa-completed", func(userId, tenantId string, userContext supertokens.UserContext) (interface{}, error) {
		return false, nil
	}, nil)

	http.ListenAndServe("SERVER ADDRESS", corsMiddleware(
		supertokens.Middleware(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
			// Handle your APIs..
			if r.URL.Path == "/like-comment" {

				session.VerifySession(&sessmodels.VerifySessionOptions{
					OverrideGlobalClaimValidators: func(globalClaimValidators []claims.SessionClaimValidator, sessionContainer sessmodels.SessionContainer, userContext supertokens.UserContext) ([]claims.SessionClaimValidator, error) {
						globalClaimValidators = append(globalClaimValidators,
							SecondFactorClaimValidator.HasValue(true, nil, nil))
						return globalClaimValidators, nil
					},
				}, likeCommentAPI).ServeHTTP(rw, r)
				return
			}
		}))))
}

func corsMiddleware(next http.Handler) http.Handler {
	return http.HandlerFunc(func(response http.ResponseWriter, r *http.Request) {
		//...
	})
}

func likeCommentAPI(w http.ResponseWriter, r *http.Request) {
	// If it comes here, the user has completed 2fa.
}
```
</Tab>
<Tab title="Python" value="python">
```python check=false reason="route fragment assumes an existing framework application"
from supertokens_python.recipe.session.framework.fastapi import verify_session
from supertokens_python.recipe.session import SessionContainer
from fastapi import Depends
from supertokens_python.recipe.session.claims import BooleanClaim

SecondFactorClaim = BooleanClaim(
    key="2fa-completed", fetch_value=lambda _, __, ___, ____, _____: False
)


@app.post("/like_comment")  
async def like_comment(
    session: SessionContainer = Depends(
        verify_session(
            # We add the SecondFactorClaim's has_value(True) validator
            override_global_claim_validators=lambda global_validators, session, user_context: global_validators
            + [SecondFactorClaim.validators.has_value(True)]
        )
    )
):
    # All validator checks have passed and the user has completed 2FA
    pass

```
</Tab>
</CodeGroup>

:::info[Important]
If the `SecondFactorClaim` claim validator fails, then the SDK will send a `403` response.
:::
