Sample login reference
The NSDK sample apps include a complete login flow that exchanges a Scaniverse login for an NSDK access token through Niantic's sample backend. This page explains how that flow works, from browser login through token exchange to NSDK authorization.
The sample login code is a reference implementation, not an SDK you ship to users. When building a production application, replace the Niantic sample backend with your own backend and identity system. The NSDK only needs the final NSDK access token — how you obtain it is up to you.
This page covers:
- How the sample login works: The token exchange flow and file structure.
- Callback scheme registration: How the sample app is configured to receive the authentication result after login.
- The sample login flow: How the sample app starts login, handles the callback, establishes a session, and exchanges session tokens for NSDK access tokens.
- Token usage in the sample app: How the sample app sets, checks, refreshes, and clears NSDK access tokens.
NSDK access tokens are JSON Web Tokens (JWTs) used to authorize requests to Niantic Spatial services.
NSDK access tokens expire after a set period. The sample app verifies the token's validity using the expiration timestamp and requests a new one when the token is missing or expired. In a production app, your backend handles token issuance — tokens should never be refreshed directly in the client.
This page focuses on client-side token usage. Backend token issuance is explained in Generate access tokens. For an overview of authorization approaches, see Authorization.
How the sample login works
The sample apps log in through Niantic's sample backend, which handles the Scaniverse login and token exchange on behalf of the client. The flow has three stages:
- Browser login: The user logs in with a Scaniverse account in a browser. The sample backend returns an NS sample session token to the app via a deep-link callback.
- Token exchange: The app exchanges the NS sample session token for an NSDK access token through a series of backend calls.
- NSDK authorization: The app passes the NSDK access token to the NSDK session. The NSDK uses this token to authorize API requests.
Only the NSDK access token is passed to the NSDK. All intermediate tokens (NS sample session tokens, NSDK refresh tokens) are managed entirely in client code and never reach the native SDK.
Token exchange detail
The sample apps use the Niantic Spatial Identity Service to exchange tokens. This is the same service your production backend would call using a service account. In the sample flow, the exchange works as follows:
| Step | Request | Returns |
|---|---|---|
| 1 | refresh_user_session_access_token with NS sample session token | Rotated NS sample session token (Set-Cookie) |
| 2 | exchange_build_refresh_token with NS sample session token | NSDK refresh token |
| 3 | refresh_build_access_token with NSDK refresh token | NSDK access token |
All requests are POST calls to the identity endpoint: https://spatial-identity.nianticspatial.com/oauth/token
The sample apps run a background refresh loop that checks token expiration every 10 seconds and re-executes the exchange before the token expires.
In a production app, your backend replaces steps 1–3. Your backend logs in the user with your own identity system, requests an NSDK access token using a service account (see Generate access tokens), and returns it to the client. The client then passes the NSDK access token to the NSDK using the same APIs shown in this guide.
File structure
Each sample app organizes its login flow into a small set of files:
| File | Purpose |
|---|---|
LoginManager.cs | Opens browser login and handles the deep-link callback |
NSSampleSessionManager.cs | Manages the NS sample session token lifecycle, refresh loop, and NSDK access token exchange |
AuthRequests.cs | HTTP request helpers for the three token exchange calls |
AuthManager.cs | UI manager for login/logout |
AuthEndpoints.cs | ScriptableObject configuration for endpoint URLs |
AuthRetryHelper.cs | Retry logic for NSDK operations that require authorization |
These files are located in the sample project's Auth directory:
nsdk-samples-csharp/Assets/Samples/Auth/Scripts/
Register a callback scheme
After login, the authentication flow redirects to a URL using the app's callback scheme. The app must be configured to handle this redirect so it can receive the authentication result.
The redirect URL uses the format:
<your-app-scheme>://signin/redirect?refreshToken=...
The registered callback scheme must match the scheme used by the authentication redirect URL. This is the URL that returns to the app after authentication.
Here is how the sample app registers its callback scheme.
In Unity, the URL scheme is configured to receive the login redirect for either iOS or Android as follows:
iOS: The sample project configures its URL scheme through Unity's Project Settings:
- Edit → Project Settings → Player → iOS tab.
- Under Other Settings → Supported URL schemes, the sample adds an entry with its scheme.
Unity stores the URL scheme in ProjectSettings/ProjectSettings.asset. When building for iOS, Unity generates an Xcode project and converts these settings into Info.plist. After updating the URL scheme, the iOS project must be rebuilt so Xcode sees the change.
Android:
The sample project registers its callback scheme in Assets/Plugins/Android/AndroidManifest.xml with an intent filter. The scheme value matches the one used in the login code.
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="nsdk-unity-samples" android:host="signin" />
</intent-filter>
The following example shows the minimum Android manifest content for this intent filter:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools">
<application>
<activity android:name="com.unity3d.player.UnityPlayerActivity" android:theme="@style/UnityThemeSelector" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="nsdk-unity-samples" android:host="signin" />
</intent-filter>
</activity>
</application>
</manifest>
The sample login flow
This section walks through each stage of the sample login flow:
- Start login
- Handle the login callback
- Establish the sample session
- Exchange session tokens for NSDK access tokens
Start login
The sample app initiates the login flow from its UI by calling the login manager. The login manager opens a browser page where the user authenticates with a Scaniverse account. After authentication completes, the browser redirects back to the app with an NS sample session token.
Before starting login, the sample app initializes the endpoints used by the login flow. The login manager reads endpoint URLs from an AuthEndpoints ScriptableObject at runtime, so it must be set before calling LoginManager.LoginRequested().
The sample project creates the AuthEndpoints asset via Create → Scriptable Objects → AuthEndpoints in the Unity Project window, then initializes it with a script:
using UnityEngine;
public class AuthEndpointsInitializer : MonoBehaviour
{
[SerializeField] private AuthEndpoints authEndpoints;
private void Awake()
{
authEndpoints.SetAsSettings();
}
}
This script is attached to a GameObject in the scene with the AuthEndpoints asset assigned in the Inspector.
The sample app starts the login flow by calling LoginManager.LoginRequested() in response to user input. Here is the login button handler:
using UnityEngine;
public class LoginController : MonoBehaviour
{
public void OnLoginTapped()
{
LoginManager.LoginRequested();
}
}
This script is added to a GameObject in the scene, and OnLoginTapped() is connected to a UI Button in the Inspector.
Handle the login callback
After authentication completes, the app receives the authentication result through a callback URL. This URL contains the NS sample session token required to establish a sample session.
Unity delivers the authentication result through a deep link. When the browser finishes authentication, it redirects to the app using the registered callback scheme.
The sample login flow handles this automatically. LoginManager.LoginRequested() sets up the deep link listener and processes the returned URL when the app resumes.
No additional callback-handling code is needed in the sample app.
Establish the sample session
After login completes, the login manager extracts the returned NS sample session token from the callback URL and stores it in NSSampleSessionManager.
The following code in LoginManager.cs completes the login flow:
private static void OnDeepLinkActivated(string url)
{
Application.deepLinkActivated -= OnDeepLinkActivated;
IsLoginInProgress = false;
var sessionToken = GetParamValue("refreshToken", url);
NSSampleSessionManager.SetNSSampleSession(sessionToken);
LoginComplete?.Invoke();
}
After login completes, the app returns to the scene and continues running. The sample session is established automatically.
Exchange session tokens for NSDK access tokens
After the NS sample session token is stored, the session manager exchanges it for an NSDK access token through three sequential HTTP requests (see Token exchange detail) and passes the result to the NSDK session.
The access flow is set up before login starts to enable NSDK features.
The sample login flow stores the NS sample session token after login. NSSampleSessionManager then exchanges it for an NSDK access token and sets it on the NSDK automatically.
NSSampleSessionManager also runs a background refresh loop that periodically checks token expiration and re-exchanges before the token expires, keeping the NSDK authorized for the duration of the app session.
Once logged in, the app uses the NSDK access token as described in the following sections.
Use tokens in your app
Whether using the sample login flow or a production backend, the NSDK APIs for managing tokens are the same. This section shows how the sample app:
- Sets NSDK access tokens on the NSDK session.
- Periodically checks if a token has expired or is about to expire.
- Clears tokens on logout.
The sample app sets the NSDK access token when initializing the NSDK session:
using NianticSpatial.NSDK.AR.Loader;
NsdkSettingsHelper.ActiveSettings.AccessToken = accessToken
The sample app checks if the NSDK access token has expired or will expire soon using AuthClient.GetAccessAuthInfo, which returns an AuthInfo object containing the expiration time in seconds since the Unix epoch:
using NianticSpatial.NSDK.AR.Auth;
/// <summary>
/// Returns true if the NSDK access token has expired or is about to expire in under a minute.
/// Uses <see cref="AuthClient.GetAccessAuthInfo"/> to read the NSDK access token's expiration.
/// </summary>
/// <returns>true if access is expired or expires in under 60 seconds; false otherwise.</returns>
public static bool IsAccessExpiredOrExpiringSoon()
{
var authInfo = AuthClient.GetAccessAuthInfo();
var currentTimeSeconds = (int)DateTimeOffset.UtcNow.ToUnixTimeSeconds();
var timeLeft = authInfo.ExpirationTime - currentTimeSeconds;
return timeLeft < ExpiringSoonThresholdSeconds;
}
On logout, the sample app clears the NSDK access token to prevent further NSDK access until a new token is obtained:
AuthClient.StaticLogout();
Adapting for production
In a production app, your backend issues and manages NSDK access tokens for each logged-in user. See Generate access tokens for server-side setup. The sample login flow demonstrates the pattern a production app would follow. The key differences are:
- Login flow. Replace the login flow. Use your own login UI and identity system instead of the Scaniverse browser login.
- Token exchange. Your production backend requests NSDK access tokens from the Niantic Spatial Identity Service using a service account (see Generate access tokens). Different users or organizations can be associated with different service accounts for asset and permission separation. The client receives only the final NSDK access token.
- Refresh pattern. The sample app's approach of monitoring token expiration on the client and requesting new tokens before they expire applies equally to production — only the token source changes.
- Passing the NSDK access token. This is identical in both cases — call
setAccessTokenwith whatever token your backend provides.
The NSDK uses all access tokens the same way, regardless of their source. Access tokens from the sample backend, your production backend, and the Scaniverse web portal are handled identically by the API.