Add one secure NeonLogin account to your application.
NeonLogin uses a browser redirect, a consent screen, and a signed callback. Register your application to receive its own signing secret and allowlist its callback domains.
Request SSO access
- Create or sign in to your NeonLogin account.
- Open the Developer Portal and register your app name, type, primary domain, and any callback subdomains.
- Copy the one-time app secret and store it only on your server.
Your registered domain is used for callback allowlisting and to select the correct app secret.
Continue to SSO accessWhat your app receives
After the user approves access, NeonLogin redirects to your callback with:
state Your original anti-forgery value client_id Registered NeonLogin app ID redirect_uri Exact registered callback URI sig_version Signed callback format version neon_id Stable NeonLogin user ID username NeonLogin username email User email address ts Unix timestamp sig HMAC-SHA256 signature flow login or link scope Requested scope
Only request and retain user data your application actually needs.
Signed callback integration
1. Send the user to NeonLogin
Create a cryptographically random state, save it in the user's server-side session, and redirect the browser:
https://teammidnite.tv/NeonLogin/?return_to=https%3A%2F%2Fexample.com%2Fauth%2Fneonlogin%2Fcallback&client_id=YOUR_APP_UID&state=RANDOM_VALUE&flow=login&scope=basic
The callback URL, client ID, flow, and scope are captured in a server-side authorization transaction. Do not change them after starting the request.
2. Verify the callback on your server
Reject the callback unless state exactly matches the unused value in the user's session, the timestamp is recent, and the signature matches.
<?php
$payload = json_encode([
'client_id' => $_GET['client_id'],
'redirect_uri' => $_GET['redirect_uri'],
'flow' => $_GET['flow'],
'scope' => $_GET['scope'],
'neon_id' => $_GET['neon_id'],
'username' => $_GET['username'],
'email' => $_GET['email'],
'ts' => $_GET['ts'],
'state' => $_GET['state'],
], JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_THROW_ON_ERROR);
$expected = hash_hmac('sha256', $payload, getenv('NEONLOGIN_APP_SECRET'));
if (!hash_equals($expected, (string) $_GET['sig'])) {
http_response_code(401);
exit('Invalid NeonLogin signature');
}
if (abs(time() - (int) $_GET['ts']) > 300) {
http_response_code(401);
exit('Expired NeonLogin callback');
}
// Also require the exact client_id, redirect_uri, flow, scope, and unused
// state value saved when this authorization attempt began.
3. Create your local session
Look up the account by neon_id, link or provision it according to your application's policy, rotate the local session ID, and mark the saved state value as consumed.
Production security checklist
- Keep the app secret server-side; never put it in JavaScript, mobile binaries, logs, or source control.
- Require HTTPS for production callback URLs.
- Use a new, unpredictable state value for every attempt and consume it once.
- Register the exact HTTPS callback URI, including port, path, and query when applicable.
- Keep the client ID, callback URI, flow, and scope bound to the original authorization transaction.
- Use
hash_equalsfor constant-time signature comparison. - Reject stale timestamps and callbacks with missing fields.
- Rotate a secret immediately if it may have been exposed.
Scopes and flows
flow=login signs a user into your app. Use flow=link when attaching NeonLogin to an account that is already authenticated. Your local application must enforce that linking request.
scope=basic is the standard signed-callback profile. The callback includes the stable user ID, username, and email shown on the consent screen, plus the registered application and callback context.
The signed callback format is a custom NeonLogin protocol, not OAuth 2.0 or OpenID Connect. New integrations use signature version 2 with a registered client_id. Legacy version 1 callbacks require an explicit legacy=1 migration flag and should be retired after migration.
Need API keys or webhooks? Create them under the registered app in the Developer Portal. Available API scopes include users:read_basic, users:read_email, and accounts:read.