File length: 8321
# Authentication - Unified Login - Verify tokens
Source: https://supertokens.com/docs/authentication/unified-login/verify-tokens
## Overview
You can verify an **OAuth2 Access Token** in two ways:
- By using a standard **JWT**, JSON Web Token, verification library
- By calling the special introspection endpoint that gets exposed through the core service
One thing to note is that, besides the standard **OAuth2** token claims, the **Unified Login** implementation includes an additional one called `stt`.
This stands for `SuperTokens Token Type`.
It ensures that the validation occurs for the correct token type:
- `0` represents a **SuperTokens Session Access Token**
- `1` represents an **OAuth2 Access Token**
- `2` represents an **OAuth2 ID Token**.
:::caution no-title
The following guide covers only **OAuth2 Tokens** verification.
For information on how to verify **SuperTokens Session Tokens** please refer to the [following section](/docs/additional-verification/session-verification/protect-api-routes).
:::
---
## Using a JWT verification library
This is the standard validation method and you should use it for most of the operations that need protection.
It indicates that the token is valid from a cryptographic standpoint and that it has not expired.
The code samples show you a basic validation scenario where the token undergoes a check for the required scope for an action to occur.
:::info
If your scenario involves a common backend with multiple frontend clients you can drop the `client_id` check.
:::
For NodeJS you can use [`jose`](https://github.com/panva/jose) to verify the token.
```tsx
const JWKS = jose.createRemoteJWKSet(new URL('jwt/jwks.json'))
// Follow this example if you are using the Authorization Code Flow
async function validateToken(jwt: string) {
const requiredScope = "";
const clientId = '';
try {
const { payload } = await jose.jwtVerify(jwt, JWKS, {
requiredClaims: ['stt', 'scp', 'client_id'],
});
if(payload.stt !== 1) return false;
if(payload.client_id !== clientId) return false;
const scopes = payload.scp as string[];
return scopes.includes(requiredScope);
} catch (err) {
return false;
}
}
```
You can use the [`jwx`](https://github.com/lestrrat-go/jwx) library to verify the token.
```go
return true
}
}
return false;
}
```
You can use the [PyJWT](https://github.com/jpadilla/pyjwt) library to verify the token.
```python
from typing import Optional, List
use Firebase\JWT\JWT;
use Firebase\JWT\Key;
function validateToken($jwt) {
$apiDomain = "";
$apiBasePath = "";
$jwksUrl = $apiDomain . $apiBasePath . '/jwt/jwks.json';
$requiredScope = "";
$clientId = "";
$jwks = json_decode(file_get_contents($jwksUrl), true);
try {
$decoded = JWT::decode($jwt, JWK::parseKeySet($jwks), 'RS256'));
if ($decoded->sst !== 1) {
return false;
}
if ($decoded->client_id !== $clientId) {
return false;
}
return in_array($requiredScope, $decoded->scp);
} catch (Exception $e) {
return false;
}
}
```
You can use the [Auth0 JWT](https://github.com/auth0/java-jwt) library to verify the token.
Here is an example of how you can do that:
```java
public class JWTVerifier {
private static final String JWKS_URL = "jwt/jwks.json";
private static final String CLIENT_ID = "";
private static Map fetchJWKS() throws Exception {
URL url = new URL(JWKS_URL);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
InputStream responseStream = connection.getInputStream();
Scanner scanner = new Scanner(responseStream, StandardCharsets.UTF_8.name());
String responseBody = scanner.useDelimiter("\\A").next();
scanner.close();
return JWT.decode(responseBody).getHeader();
}
public static boolean validateToken(String token) {
try {
Map jwks = fetchJWKS();
Algorithm algorithm = Algorithm.RSA256(jwks.get("x5c"), null);
JWTVerifier verifier = JWT.require(algorithm)
.build();
DecodedJWT jwt = verifier.verify(token);
if(jwt.getClaim("sst").asInt() != 1) {
return false;
}
if(jwt.getClaim("client_id").asString() != CLIENT_ID) {
return false;
}
List scopes = jwt.getClaim("scp").asList();
return scopes.contains(requiredScope);
} catch (Exception e) {
return false;
}
}
}
```
You can use the [IdentityModel](https://github.com/IdentityModel/IdentityModel) library to verify the token.
```csharp
using System;
using System.Linq;
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Net.Http;
using System.Threading.Tasks;
using Newtonsoft.Json.Linq;
class AuthorizationCodeTokenValidator
{
static async Task ValidateToken(string jwtStr)
{
string apiDomain = "";
string apiBasePath = "";
string clientId = "";
string requiredScope = "";
HttpClient client = new HttpClient();
var response = await client.GetStringAsync($"//jwt/jwks.json");
var jwks = new JsonWebKeySet(response);
var tokenHandler = new JwtSecurityTokenHandler();
var validationParameters = new TokenValidationParameters
{
IssuerSigningKeys = jwks.Keys
};
try
{
SecurityToken validatedToken;
var principal = tokenHandler.ValidateToken(jwtStr, validationParameters, out validatedToken);
var claims = principal.Claims.ToDictionary(c => c.Type, c => c.Value);
if (!claims.ContainsKey("stt") || claims["stt"] != "1")
{
return false;
}
if (!claims.ContainsKey("client_id") || claims["client_id"] != clientId)
{
return false;
}
var scopes = claims["scp"].Split(" ");
if (!scopes.Contains(requiredScope))
{
return false;
}
return true;
}
catch (Exception)
{
return false;
}
}
}
```
### Email verification
If you are using email and password based authentication, and you want to validate if the user has verified their email, you must check if the `email_verified` claim is true.
---
## Using the token introspection API
When a user logs out, their token gets removed from the **SuperTokens Core** database.
That change does not reflect in token validation process that uses a JWT verification library.
The token remains valid until its expiration time.
To ensure that the token remains valid, you can directly call the **SuperTokens Core** service.
It is advisable to perform this process for high security operations to avoid the risk of a malicious agent using a token.
Here is an example of how you can use this validation method:
```tsx
async function validateToken(token: string) {
const { status } = await OAuth2Provider.validateOAuth2AccessToken(
token,
{
clientId: "",
scopes: [""],
},
true
);
return status === "OK";
}
```
:::caution
The Go SDK does not support creating OAuth2 providers.
:::
```python
from supertokens_python.recipe.oauth2provider.interfaces import OAuth2TokenValidationRequirements