Verify user identity
Overview
When the user authenticates with Ronin Waypoint, your game receives an ID token, which is a JSON web token (JWT) containing the user's information.
To ensure the user is who they claim to be, you need to verify the ID token by sending it to your backend server and performing the verification as described in this guide. Once verified, your backend server can issue an access token to the user, allowing them to interact with your backend server securely.
Steps
Step 1. Obtain the public keys
To verify the ID token, you need to obtain the public keys used to sign the token. These keys are issued by Sky Mavis and are located at https://waypoint.roninchain.com/.well-known/jwks.json.
By default, the signing key is rotated every 6 weeks. This means you need to programmatically or manually update your keys as they rotate. The previous key remains valid for 7 days after rotation to allow time for you to make the update.
The following example shows two public keys: the current key used to sign all new tokens, and the previous key that has been rotated out. The example is a JSON Web Key Set (JWKS) object that contains a keys
array of JWK keys. Each key contains the key type (kty
), the key use (use
), the key ID (kid
), the curve (crv
), and the x
and y
coordinates of the public key.
{
"keys": [
{
"kty": "EC",
"use": "sig",
"kid": "018e085d-353d-73ac-8006-c43f376631f1",
"crv": "P-256",
"x": "9rB5mWnYHdobqkn8wYG4BzM7-uC5-QOokatjct3DQU8",
"y": "cECJGhKRW__VSuYS7jxtnMDArwkrHff_P9B8xHMMhYI"
},
{
"kty": "EC",
"use": "sig",
"kid": "018e085d-2e3f-7474-8007-21c0408ba33e",
"crv": "P-256",
"x": "CGlCzoxUjGUoGnryNnmzwzyLgzqwxaSrieb0ufxliiw",
"y": "pK3QizTfodV9CFGnV-hC9dLEzBw6Gp7zldWbMWPqbog"
}
]
}
Step 2. Verify the ID token
Verify manually
To verify the ID token manually, follow these steps:
-
Copy the JWT token from the response.
-
Visit JSON Web Token Verifier.
-
Paste the JWT token into the Enter JWT field.
-
Paste the URL of the JWKs endpoint (
https://waypoint.roninchain.com/.well-known/jwks.json
) into the Enter jwks endpoint or issuer domain field. -
Review the decoded token to ensure it contains the expected user information.
Verify programmatically
-
Get the client ID for your app from the Developer Console under Products > Waypoint Service > CLIENT ID (APPLICATION ID).
-
Use the following code snippets to verify the ID token in your backend server:
- Go
- Python
- JavaScript
package main
import (
"context"
"encoding/json"
"fmt"
"net/http"
"github.com/coreos/go-oidc/v3/oidc"
)
var (
issuer = "https://id.skymavis.com"
// Example client ID
clientID = "52b85454-dd6f-4b0f-8d7a-9e30a33e387e"
certsURL = "https://waypoint.roninchain.com/.well-known/jwks.json"
// The Application Audience (AUD) tag for your application
config = &oidc.Config{
ClientID: clientID,
}
keySet = oidc.NewRemoteKeySet(context.TODO(), certsURL)
verifier = oidc.NewVerifier(issuer, keySet, config)
)
// AuthWaypointRequest represents the request body for authentication with Sky Mavis
type AuthWaypointRequest struct {
IDToken string `json:"id_token"`
}
// AuthWaypointResponse body for authentication with Sky Mavis
type AuthWaypointResponse struct {
AccessToken string `json:"access_token"`
// Other information
}
// AuthWaypoint is a handler to verify the ID token and issue an access token
func AuthWaypoint(w http.ResponseWriter, r *http.Request) {
req := &AuthWaypointRequest{}
if err := json.NewDecoder(r.Body).Decode(req); err != nil {
http.Error(w, "malformed request body", 400)
return
}
// Verify the ID token
id, err := verifier.Verify(r.Context(), req.IDToken)
if err != nil {
http.Error(w, fmt.Sprintf("ID token is not valid: %s", err.Error()), 400)
return
}
// Perform verification and issue an access token for id.Subject
json.NewEncoder(w).Encode(&AuthWaypointResponse{
AccessToken: "Access token for " + id.Subject,
})
}
func main() {
http.HandleFunc("POST /auth/waypoint", AuthWaypoint)
http.ListenAndServe(":3000", nil)
}
Install the required packages:
pip install flask requests PyJWT flask_json
Create a new .py
file and add the following code:
from flask import Flask, request
import jwt
import base64
import json
from flask_json import JsonError, json_response, as_json
app = Flask(__name__)
app.config['JSON_ADD_STATUS'] = False
# Example client ID
client_id = "52b85454-dd6f-4b0f-8d7a-9e30a33e387e"
# Ronin Waypoint domain information
issuer = "https://id.skymavis.com"
certURI = "https://waypoint.roninchain.com/.well-known/jwks.json"
jwks_client = jwt.PyJWKClient(certURI, headers={'User-Agent': 'Python3'})
@app.post('/auth/waypoint')
@as_json
def auth_waypoint():
body = request.get_json(force=True)
try:
id_token = str(body['id_token'])
except (KeyError, TypeError, ValueError):
raise JsonError(description='Invalid value.')
signing_key = jwks_client.get_signing_key_from_jwt(id_token)
# Decode the JWT token to get payload and header
try:
data = jwt.api_jwt.decode_complete(
id_token,
key=signing_key.key,
algorithms=["RS256"],
audience=client_id,
)
except:
raise JsonError(description='Invalid ID Token.')
payload = data["payload"]
# Perform verification and issue an access token for payload['sub']
return dict(access_token="access token for: " + payload['sub'])
if __name__ == '__main__':
app.run(port=3000)
const express = require('express');
const jwksClient = require('jwks-rsa');
const jwt = require('jsonwebtoken');
// The Application Client ID (AUD) tag for your app
const clientId = process.env.SKYMAVIS_CLIENT_ID || '52b85454-dd6f-4b0f-8d7a-9e30a33e387e';
const issuer = process.env.SKYMAVIS_ISSUER || 'https://id.skymavis.com';
const certURL = 'https://waypoint.roninchain.com/.well-known/jwks.json';
const client = jwksClient({
jwksUri: certURL
});
const getKey = (header, callback) => {
client.getSigningKey(header.kid, function(err, key) {
callback(err, key?.getPublicKey());
});
}
// authWaypoint is a handler to verify the ID token and issue an access token
const authWaypoint = (req, res, next) => {
const token = req.body.id_token
// Ensure the incoming request has the ID token
if (!token) {
return res.status(403).send({ status: false, message: 'missing required cf authorization token' });
}
jwt.verify(token, getKey, { audience: clientId }, (err, decoded) => {
if (err) {
return res.status(403).send({ status: false, message: 'invalid token' + err});
}
// Perform verification and issue an access token for decoded.sub
return res.send({
accessToken: "access token for " + decoded.sub
})
});
}
const app = express();
app.use(express.json());
app.post('/auth/waypoint', authWaypoint);
app.listen(3000)
Step 3. Issue an access token
After verifying the ID token, issue an access token to the user. The access token allows the user to interact with your backend server.
See also
ID Token and Access Token: What's the Difference? (auth0.com)