Skip to content
  • Our Product
    • Namazu Elements
      • What is Elements?
      • Why open source?
      • Docs
        • Namazu Elements in Five Minutes or Less
        • RESTful APIs Library
        • Security Model
        • Accessing the Web UI (CMS)

    Our Product

    A logomark with three layered rhombuses adorning the lettermark that says Elements in bold all-caps sans-serif letters.
    • What is Namazu Elements? Discover our easy-to-use backend network solution built for online games. Rapidly enables full-scale multiplayer games or online solo adventures.
    • Why open source? Is there a truly open source server backend for connected games? There is now. Download and run a local copy of Namazu Elements and try it for yourself.
    Download Namazu Elements

    Get started

    • Quick start Read our Elements 5-minute quick start guide
    • Documentation Read our developer docs for learning more about Elements
    • RESTful APIs A full list of core API specs for working with the Elements framework
    • Security An overview of the server-authoritative security model of Elements
    • Accessing the CMS Manage your game with ease via the Namazu Elements CMS.

    Co-development Reimagined

    • Best real-time game backends in 2026 If you're researching an alternative to your current backend solution, we've prepared a report of all of the backend solutions on the market in 2026 and how Namazu Elements compares.
      Co-dev

    Recent Posts

    • The watercolor-styled Namazu Studios logo over a giant namazu lurking in the depth
      Namazu Studios Featured in San Diego Business Journal
      22 Sep 2025 Press
    • Namazu Elements 3.1 Released – Service Layer Fixes, Secure APIs, and Steam Bug Fix
      22 Apr 2025 Release Notes
  • Case Studies
  • About Us
  • News
  • Services
  • Book a call
namazu-studios-logo
Book a call
Popular Search Roblox

Getting Started

  • Namazu Elements in Five Minutes or Less
  • Overview
  • Accessing the Web UI (CMS)
  • CMS Feature Overview

Fundamentals

  • Why You Need a Server (and What “Authoritative” Means)
  • Elements as a Game Runtime
  • Where Your Authoritative Code Runs
  • Lifecycles and Flows

General Concepts

  • Custom Elements
  • Data Models
  • Security Model
  • N-Tier Architecture

Namazu Elements Core Features

  • Email Service
  • Applications
  • Sessions
  • Users and Profiles
  • Digital Goods
  • Progress and Missions
  • Progress and Missions (3.4+)
  • Leaderboards
  • Matchmaking – Comprehensive Guide
  • Friends
  • Followers
  • Product Bundles and SKUs
  • Item Ledger
  • Receipts
  • Reward Issuances
  • Save Data
  • Metadata
  • Metadata (3.4+)
  • Queries
  • User Authentication / Sign In
    • What is a User?
    • Email Verification
    • User Authentication in Elements
    • Account Linking
    • Setting Up Twitch OIDC Login (Backend)
    • OIDC Login for Thick Clients (Browser Redirect Flow)
    • Auth Schemes
      • Auth Schemes
      • OAuth2
      • OIDC
  • Features
    • Web3
      • Wallets
      • Vaults
      • Omni Chain Support
      • Smart Contracts
        • Smart Contracts
  • Queries
    • Advanced Operators
    • Object Graph Navigation
    • Boolean Queries
    • Base Query Syntax
  • Advanced Operators
    • .name
    • .ref

Your Game Code - Adding Custom Elements

  • Custom Code Overview
  • Windows Setup
  • Mac OS Setup
  • Ubuntu Linux Setup
  • Element Anatomy: A Technical Deep Dive
  • Introduction to Guice and Jakarta in Elements
  • Structuring your Element
  • Events
  • Packaging an Element with Maven
  • Deploying an Element
  • Preparing for code generation
  • Properties
  • Websockets
  • RESTful APIs
  • Direct MongoDB Access (3.5+)
  • Building the Example Element: A Complete Walkthrough
  • Building the Kotlin Example Element: A Complete Walkthrough

Configuration

  • Configuring External URLs for Deployment
  • Matchmaking – Comprehensive Guide
  • Direct Database Access and Batch Configuration
  • Connecting Namazu Elements to a TLS-Enabled MongoDB Replica Set
  • Batch Samples
    • Mission Upload Bash Script Sample
    • Item Upload Bash Script Sample

RESTful APIs

  • Importing into Postman
  • RESTful APIs Library
  • Swagger and Swagger UI

Add-Ons

  • Crossplay
    • Crossfire Client Libraries (JVM & Browser)
    • Crossfire Protocol Reference
    • Crossfire: Custom Matchmaking Algorithms
    • Namazu Crossfire (Multiplayer)
    • Deploying Namazu Crossfire in your game
  • Roblox
    • Roblox Overview
    • Secure Player Authentication & Registration
    • Global Matchmaking
    • Roblox Security Best Practices
  • Container on Demand
    • Namazu Conductor
    • Namazu Conductor Admin API
    • Configuring Namazu Conductor Providers
  • Commerce
    • Stripe
      • Stripe
      • Configuring the Stripe Element
      • Stripe REST API Reference
      • Stripe REST API Reference

Game Engine & Client Support

  • Unity
    • Elements Unity Plugin
    • Unity Crossfire Plugin
  • Gamemaker
    • Incorporating GMEXT-Elements into a GameMaker Project

Troubleshooting

  • Common Issues with Docker
  • Local SDK
    • Unable to deploy application : dev.getelements.elements.sdk.exception.SdkElementNotFoundException
    • Could not load class : java.lang.NoClassDefFoundError
  • Namazu Elements Community Edition
    • Common Issues with Docker
    • Unable to deploy application : dev.getelements.elements.sdk.exception.SdkElementNotFoundException
    • Running in the IDE
      • Exception in monitor thread while connecting to server localhost:27017
      • Could not deployAvailableApplications Jetty server Failed to bind to /0.0.0.0:8080 Address already in use

Releases

  • 3.8 Release Notes
  • 3.7 Release Notes
  • 3.6 Release Notes
  • 3.5 Release Notes
  • 3.4 Release Notes
  • 3.3 Release Notes
  • 3.2 Release Notes
  • 3.1 Release Notes
View Categories
  • Home
  • Docs
  • Namazu Elements Core Features
  • User Authentication / Sign In
  • Setting Up Twitch OIDC Login (Backend)

Setting Up Twitch OIDC Login (Backend)

Est. read time: 8 min read

AI Doc Summarizer Doc Summary
AI Doc Summarizer Thinking Thinking

This walks through configuring Twitch as an OIDC provider for the browser-redirect login
flow (see OIDC Login for Thick Clients (Browser Redirect Flow for the client-side sequence). It covers registering the app with Twitch and creating the OidcProviderConfiguration on the Elements server.

This is Distinct from the older, direct id_token validation path (OidcAuthScheme, seeded
by DefaultOidcSchemeConfiguration) which just validates a JWT you already possess.
This one drives the full authorization-code flow: opening Twitch’s login page, handling the
redirect, and exchanging the code for tokens.

Step 1: Determine your Elements callback URL #

Before registering anything with Twitch, figure out the exact URL Elements will use as the
OAuth redirect target. It’s always:

{API_OUTSIDE_URL}/OIDC/twitch/callback

API_OUTSIDE_URL is this server’s configured public base URL (the dev.getelements.elements.api.url
named config value; defaults to http://localhost:8080/api/REST if unset). For a default
local dev setup, the callback URL is:

http://localhost:8080/api/REST/OIDC/twitch/callback

This must match what you register with Twitch byte-for-byte including scheme, host, port, path,
and trailing slash all count. Twitch rejects any mismatch with error=redirect_mismatch, otherwise.

Alternatively, you can always find the URL base by looking at the host part in the admin URL for your instance of Namazu Elements.

Step 2: Register an app in the Twitch Developer Console #

  1. Go to the Twitch Developer Console and create a new
    Application.
  2. Under OAuth Redirect URLs, add the exact callback URL from Step 1.
  3. Specify Category that best relates to your particular project or game.
  4. Select Client Type as Confidential.
  5. Select Organization as it applies to your particular project or game.

At this point, Twitch will direct you back to the listing of all Applications you’ve created.

  1. Click the Manage button on the Application you just created.
  2. If there is no secret yet, then click “New Secret”
    • Note: Regenerating an old secret will cause existing applications to immediately cease to function. This may cause downtime on an existin Application.

Step 3: Create the provider configuration in Elements #

This requires a SUPERUSER Session in the admin console.

  1. In the left sidebar, open the Auth category and select OIDC Providers.
  2. Click + Create OIDC Provider to open the creation dialog.
  3. Fill in the fields:
    • name: twitch this becomes part of the callback URL (/OIDC/twitch/callback) and
      the key used for User.linkedAccountProfiles.
    • name: twitch this becomes part of the callback URL (/OIDC/twitch/callback) and
      the key used for User.linkedAccountProfiles.
    • discoveryUrl: https://id.twitch.tv/OAuth2/.well-known/openid-configuration
    • clientId: your Twitch Client id
    • clientSecret: your Twitch Client Secret. This field is never pre-filled; the API
      never echoes a saved secret back, so it always shows blank if you reopen this
      configuration to edit it later. Leave it blank on an edit to keep the existing secret.
    • scopes: a tag input. Type openid, press Space or Enter, then type
      User:read:email and press Space or Enter. Both scopes are required; see below.
    • redirectUri: leave Use built-in Elements redirect checked so Elements
      auto-computes the callback URL from Step 1. Only uncheck it and enter a URL manually if
      you registered a different callback URL with Twitch; if you do, it must match that
      registered value byte-for-byte, same rule as above.
    • extraAuthorizeParams: a raw JSON textarea. Paste:
      json { "claims": "{\"id_token\":{\"email\":null,\"email_verified\":null,\"preferred_username\":null}}" }
    • tokenEndpointAuthMethod: select Client Secret Post from the dropdown. Do not
      leave this at the default Client Secret Basic — see below.
    • successRedirectUrl / errorRedirectUrl: optional, only needed for the
      browser-redirect thick-client flow.
  4. Save. Elements resolves Twitch’s discovery document immediately and auto-provisions the matching OidcAuthScheme by issuer no separate manual step needed.

Field values that matter more than they look like they should #

  • scopes must include "openid". Twitch’s token endpoint only returns an id_token if
    the authorization request included the openid scope. Without it, you’ll get a 200 from
    the token exchange but no id_token in the response, which Elements reports as Token endpoint response did not contain an id_token.
  • tokenEndpointAuthMethod must be CLIENT_SECRET_POST. This field defaults to
    CLIENT_SECRET_BASIC (HTTP Basic auth) if omitted, which is legal per RFC 6749 — but
    Twitch’s token endpoint doesn’t read credentials from the Authorization header at all. If
    left at the default, token exchange fails with {"status":400,"message":"missing client secret"} (or missing client id) even though the credentials were sent, just in the wrong
    place as far as Twitch is concerned.
  • Getting email requires two separate things, not one. The User:read:email scope is a
    prerequisite per Twitch’s docs, but it is not sufficient by itself — Twitch’s id_token only
    ever carries a minimal default claim set (aud, azp, exp, iat, iss, sub) unless you
    also request extra claims via the non-standard claims authorize parameter, set through
    extraAuthorizeParams as shown above. Skip either one and email simply won’t be in the
    id_token, and Elements will have nothing to link. Elements trusts any email claim returned
    by a configured provider as already verified — it does not check email_verified at all
    (some providers omit that claim, or encode it as a non-boolean type). The example above still
    requests email_verified for completeness, but it’s informational only; Elements ignores it.

Profile claims: what gets linked onto the User record #

Beyond sub (linked as a UserUid) and email (linked as a UserUid + copied to User.email),
Elements also captures standard OIDC Profile-scope claims — given_name, family_name,
preferred_username, and others — whenever a provider returns them:

  • On a new anonymous login (AnonOidcAuthService, the flow this doc walks through), any of
    preferred_username → User.preferredUsername, given_name → User.firstName, and
    family_name → User.lastName that are present get set on the new User directly. On a
    returning User, the same claims only fill in a field if it’s currently blank — an existing
    value (set by an admin, the User, or an earlier login) is never overwritten.
  • Every provider’s full set of returned Profile claims is also snapshotted, as-is, into
    User.linkedAccountProfiles, keyed by the OIDC scheme’s name — this is a per-provider audit
    trail (visible in the admin console as a breakout view on the User record), not subject to the
    fill-only-if-blank rule above, and is captured on both new and returning logins, and when
    linking an additional scheme to an already-authenticated User (UserOidcAuthService) — though
    that linking path does not touch the flat preferredUsername/firstName/lastName fields,
    only linkedAccountProfiles.

For Twitch specifically: request preferred_username via the claims extra authorize parameter
as shown in Step 3 to get it linked. Twitch has no “real name” concept in its public API/OIDC
surface (only username/display name), so given_name/family_name/name will never be present
regardless of configuration. Profile.displayName is unrelated to all of this — it’s always a
randomly generated name unless set explicitly via the Profile API.

Step 4: Verify in the admin console #

The OIDC Providers resource in the admin console (under the Auth category) shows the
saved configuration. clientSecret is write-only — it’s never echoed back by the API, so the
console always shows it blank on edit; leave it blank when editing to keep the existing
secret, or type a new one to rotate it.

Step 5: Test the login #

Using the thick-client sequence (see OIDC Login for Thick Clients for full detail):

curl -X POST http://localhost:8080/api/REST/OIDC/Session \
  -H 'Content-Type: Application/json' \
  -d '{"provider": "twitch"}'

Open the returned authorizeUrl in a browser, complete the Twitch login, then poll:

curl http://localhost:8080/api/REST/OIDC/Session/{handle}

until status is COMPLETE (with the Session) or FAILED. Two things to know about polling:
COMPLETE is only returned once, on the poll that first observes it — a second poll for the same
handle returns HTTP 404, not another COMPLETE body. An unknown or expired handle also returns
404 rather than a body with status: EXPIRED, so a 404 on its own doesn’t necessarily mean the
login failed; check whether you’d already consumed a COMPLETE response before treating it as one.

Troubleshooting #

SymptomCauseFix
Browser lands on ...?error=redirect_mismatchThe redirect_uri Elements sent doesn’t exactly match what’s registered in Twitch’s consoleCompare the exact redirectUri on the provider config against Twitch’s registered OAuth Redirect URL; they must match byte-for-byte
Token exchange fails: {"status":400,"message":"missing client id"} or "missing client secret"tokenEndpointAuthMethod is CLIENT_SECRET_BASIC (the default); Twitch ignores the Authorization headerSet tokenEndpointAuthMethod to CLIENT_SECRET_POST on the provider config
ForbiddenException: Token endpoint response did not contain an id_tokenscopes doesn’t include openidAdd "openid" to the provider config’s scopes
Token exchange failed with status 400 with no other detail returned to the callerExpected — the actual provider error is intentionally not exposed to the API callerCheck the server logs; the token endpoint’s error body is logged at error level (OidcLoginAttemptOperations.exchangeCodeForIdToken)
Logged in, but no email UserUid and User.email is emptyemail missing from the id_token — either User:read:email scope is missing or the claims extra authorize param isn’t set (email_verified is not required; Elements doesn’t check it)Add User:read:email to scopes and set extraAuthorizeParams.claims as shown above
Logged in, but User.preferredUsername wasn’t setpreferred_username missing from the id_token, the User already had a preferredUsername set (fill-only-if-blank, never overwritten), or you’re testing the link-account flow rather than login (that path only writes linkedAccountProfiles, not the flat field)Confirm extraAuthorizeParams.claims requests preferred_username under id_token; check User.linkedAccountProfiles["twitch"] to see exactly what the token returned

What are your Feelings
Still stuck? How can we help?

How can we help?

Updated on August 13, 2026
Account LinkingOIDC Login for Thick Clients (Browser Redirect Flow)
Table of Contents
  • Step 1: Determine your Elements callback URL
  • Step 2: Register an app in the Twitch Developer Console
  • Step 3: Create the provider configuration in Elements
    • Field values that matter more than they look like they should
    • Profile claims: what gets linked onto the User record
  • Step 4: Verify in the admin console
  • Step 5: Test the login
  • Troubleshooting
  • Documentation
  • Terms of Service
  • Privacy Policy
  • Contact us
  • Linkedin
  • Join our Discord

Namazu Studios LLC is powered by Namazu Elements, an open source modular backend framework for connected games.

Namazu Elements
  • Download
  • About Elements
  • Open source
  • Documentation
  • Support
Namazu Studios
  • Case Studies
  • About Us
  • News
Best realtime game backends 2026
Get in Touch
  • info@namazustudios.com
  • Book a call
  • (619) 862-2890
  • Linkedin
  • Discord

©2008-2026 Namazu Studios. All Rights Reserved.