Junior Accounts
Junior accounts allow minors (users under a configurable age threshold) to participate on your platform under the supervision of a guardian. This guide explains how junior accounts work, how they differ from standard adult accounts, and what your integration needs to handle.
Postman Collection
For full request/response examples covering the junior account lifecycle, use the Postman collection:
Overview
A junior account is a special account type designed for minors. It differs from a standard account in several important ways:
- Username-based authentication -- Juniors log in with an alphanumeric username (e.g.
junior123) and password, not an email address. - Guardian supervision -- Every junior account is linked to a guardian's email address. The guardian receives verification emails and other communications on behalf of the junior.
- Restricted by default -- Junior accounts carry distinct roles and a
minor_idfield in their JWT, so your application can enforce age-appropriate restrictions. - Upgradeable -- Once a junior reaches the configured age threshold (typically 16), they can upgrade to a full adult account.
Registration Flow
Registering a junior account requires the following information:
| Field | Required | Description |
|---|---|---|
client_id | Yes | Your Cortex client ID. |
device_id | Yes | Unique device identifier (UUID). |
username | Yes | An alphanumeric string that becomes the junior's login identifier (e.g. junior123). |
password | Yes | Must meet the same password policy as adult accounts. |
guardian_email | Yes | The email address of the guardian who will oversee this account. |
email | No | The junior's own email address, if they have one. If omitted, the guardian's email is used for all communications. |
first_name | No | The junior's first name. |
last_name | No | The junior's last name. |
language | No | BCP 47 language tag (e.g. en). |
register_source | No | Source of the registration (e.g. web, app). |
register_type | No | Type of registration. |
register_platform | No | Platform (e.g. ios, android, web). |
When a junior account is registered:
- The account is created with a status of
guardian_consent_required. - A verification email is sent -- either to the guardian or to the junior, depending on the client configuration.
- The response includes tokens, but the
statusfield will beguardian_consent_requiredrather thansuccess, signaling that the account is not yet fully active.
Important: Your application should check the
statusfield in the token response. If it isguardian_consent_required, you should inform the user that their guardian needs to verify the account before it is fully active.
Guardian Verification
Some clients have guardian verification enabled. When this is active, the flow works as follows:
- If the guardian already has a verified SSO account, a verification email is sent to the guardian asking them to consent to the junior's account.
- If the guardian has an unverified SSO account, a verification email is sent to the guardian first. Once the guardian verifies their own account, the junior verification email is then sent automatically.
- If the guardian does not have an SSO account, a "create account" email is sent to the guardian. They must register and verify before the junior account becomes active.
Once the guardian verifies, the junior account is assigned the ROLE_GUARDIANVERIFIED_* role.
Email Verification
- If the junior has their own email address, a separate verification email is sent to that address. Once verified, the junior receives the
ROLE_VERIFIED_*role. - If the junior does not have their own email, they receive the
ROLE_VERIFIED_*role when the guardian verifies the account (since all communications go through the guardian).
In summary, a fully verified junior account (with guardian verification enabled) will have both ROLE_VERIFIED_* and ROLE_GUARDIANVERIFIED_*.
Authentication
Junior Login
Juniors authenticate using their username and password -- not an email address. The login grant type is the standard password grant, but with the username field containing the junior's alphanumeric username.
The token response for a junior login is structurally identical to an adult login, but the JWT payload contains additional junior-specific fields (see Roles and JWT below).
Guardian Login to Junior Account
Endpoint: POST /me/accounts/login (form-encoded, authenticated as the guardian).
A guardian who is already logged in can mint tokens for one of their linked juniors without the junior's password. This is typically used by guardian-facing UIs to "switch into" a junior account so the guardian can manage it or act on the junior's behalf.
Preconditions
- The caller must be authenticated with a guardian access token (i.e. the JWT has no
minor_id). - The guardian's own email must be verified (
email_verified: true). The endpoint returns400 account_not_verifiedotherwise. - The supplied
refresh_tokenmust belong to the guardian, not be expired, and have been issued for the samedevice_idsupplied in the request. - The
account_idmust correspond to a junior whoseguardian_emailmatches the guardian's email and is registered under the sameclient_id. Juniors linked under a different client are rejected.
Request
| Field | Required | Description |
|---|---|---|
account_id | Yes | The junior's auth user ID (the id returned by GET /me/accounts/linked). |
device_id | Yes | UUID identifying the device. Must match the device_id the refresh token was issued to. |
refresh_token | Yes | The guardian's current refresh token. |
token_version | No | Optional token version override; defaults to the client's configured version. |
POST /me/accounts/login HTTP/1.1
Host: oauth.fanscore.com
Authorization: Bearer <guardian_access_token>
Content-Type: application/x-www-form-urlencoded
account_id=77112&device_id=7b1c1f5c-9c2a-4e7e-9a6b-3b5e2c7f1a22&refresh_token=<guardian_refresh_token>Response -- structurally identical to a password-grant token response, but issued for the junior. The returned JWT carries the junior's minor_id and junior-specific roles:
{
"access_token": "<junior_access_token>",
"refresh_token": "<junior_refresh_token>",
"token_type": "Bearer",
"expires_in": 3600,
"status": "success"
}The guardian's own session is not invalidated -- the guardian keeps their existing tokens and simply receives an additional token pair scoped to the junior.
Common errors
| Status | Code | Cause |
|---|---|---|
| 400 | invalid_refresh_token | Refresh token missing, malformed, expired, or issued for a different device_id. |
| 400 | account_not_verified | Guardian's own email is not yet verified. |
| 400 | invalid_request | account_id is not a junior linked to this guardian under this client. |
| 404 | user_not_found | Guardian's auth user no longer exists. |
Roles and JWT
Junior-Specific JWT Claims
When a junior account is authenticated, the JWT contains additional fields that distinguish it from an adult account:
| Claim | Type | Description |
|---|---|---|
minor_id | string | The junior's username/identifier (e.g. junior123). Present only for junior accounts. This is the primary way to detect a junior user. |
guardian_email | string (nullable) | The guardian's email address. Present only when minor_id is set. May be omitted from the JWT if not set. |
To determine if a user is a junior: check whether the minor_id claim is present and non-empty in the JWT. If it is, the user is a junior.
Roles
Junior accounts can have the following roles in the authorities array of the JWT:
| Role | Meaning |
|---|---|
ROLE_USER_* | Standard user role, assigned to all registered accounts. |
ROLE_VERIFIED_* | The junior's email (or guardian's email, if the junior has none) has been verified. |
ROLE_GUARDIANVERIFIED_* | The guardian has verified and consented to the junior's account. Only present when guardian verification is enabled for the client. |
Note: A junior account will not have
ROLE_VERIFIED_*orROLE_GUARDIANVERIFIED_*until the appropriate verification steps are complete. Your application should check for these roles if you need to gate features behind verified status.
Example JWT Payload (Decoded)
{
"sub": 77112,
"client_id": "YOURCLIENT",
"first_name": "User",
"email": "[email protected]",
"email_verified": true,
"minor_id": "junior123",
"guardian_email": "[email protected]",
"scope": ["open_id", "profile"],
"authorities": [
"ROLE_USER_*",
"ROLE_VERIFIED_*",
"ROLE_GUARDIANVERIFIED_*"
],
"exp": 1613489775,
"jti": "cd9c4b5b-d181-404c-8564-f40b3860bcf6",
"iss": "CortexTech"
}Note: The
guardian_emailclaim may be absent if the guardian email is not set. Additional claims such asauth_time,sid, andentitlementsmay also be present depending on client configuration.
Account Upgrade
When a junior reaches the configured age threshold (default: 16 years old), they become eligible to upgrade to a full adult account. The age is validated against the date of birth stored in the user's profile.
How It Works
- The junior (or their guardian) initiates an upgrade request and provides an email address for the new adult account.
- The system verifies the junior's age by checking their date of birth in the profile service. If the junior is not old enough, the request is rejected.
- The provided email must not already be in use by another account.
- On success:
- The
minor_idandguardian_emailfields are cleared from the account. - Junior-specific roles are removed, including
ROLE_GUARDIANVERIFIED_*,ROLE_PROFILECOMPLETE_*, andROLE_MARKETINGPREFERENCESCOMPLETE_*. - If the junior's email was not yet verified,
ROLE_VERIFIED_*is also removed. - If the new email differs from the existing one, a verification email is sent and the account is marked as unverified until confirmed.
- The user's profile is updated to reflect the upgrade.
- The
After upgrading, the account behaves exactly like a standard adult account. The JWT will no longer contain the minor_id claim, and the user logs in with their email address instead of a username.
Important: The age threshold may vary by client. The default is 16, but this is configurable per client in the SSO configuration.
Endpoint
Endpoint: POST /me/upgradeAccount (authenticated as the junior).
Request:
POST /me/upgradeAccount HTTP/1.1
Host: oauth.fanscore.com
Authorization: Bearer <junior_access_token>
Content-Type: application/json
{
"email": "[email protected]"
}Response: 200 OK with an empty body. After upgrade, the user must log in with the supplied email using the password grant; the old username is no longer valid.
Common errors
| Status | Code | Cause |
|---|---|---|
| 400 | minor_age_invalid | Junior has not reached the configured upgrade age (default 16). |
| 400 | account_exists | An account already exists for the supplied email under this client. |
| 403 | account_not_minor | Caller is not a junior account. |
| 404 | user_not_found | Caller's auth user no longer exists. |
Linked Accounts
Endpoint: GET /me/accounts/linked (requires a valid access token for the caller).
The linked accounts endpoint allows both guardians and juniors to discover their related accounts. The caller's role is inferred from the JWT. Guardians see their juniors, juniors see their guardian. Results are scoped by the JWT's client_id; juniors linked under a different client are not returned.
- For a guardian: returns a list of all junior accounts linked to their email address. Each entry includes the junior's
id,first_name,last_name,email,minor_id(username), andaccount_type. - For a junior: returns the guardian's account information (if the guardian has an SSO account), with the same fields.
minor_idis omitted for the guardian entry.
Each linked account includes an account_type field:
GUARDIAN-- the account is a guardian (returned when a junior queries their linked accounts).MINOR-- the account is a junior (returned when a guardian queries their linked accounts).
Example -- Guardian fetching their linked juniors
Request:
GET /me/accounts/linked HTTP/1.1
Host: oauth.fanscore.com
Authorization: Bearer <guardian_access_token>Response (200 OK):
[
{
"id": "77112",
"first_name": "Alex",
"last_name": "Smith",
"email": "[email protected]",
"minor_id": "junior123",
"account_type": "MINOR"
},
{
"id": "77113",
"first_name": "Jamie",
"last_name": "Smith",
"email": "[email protected]",
"minor_id": "jamie456",
"account_type": "MINOR"
}
]Notes:
emailis the junior's own email if one was set at registration; otherwise it falls back to the guardian's email (the address used to register the junior).minor_idis the junior's login username -- use this with thepasswordgrant if you need the junior to log in directly.idis the junior's auth user ID -- this is the value you pass asaccount_idto the guardian-login endpoint (see Guardian Login to Junior Account).- If the caller is a junior, the response is at most one entry (the guardian) with
account_type: GUARDIANand nominor_id. If the guardian has not yet created an SSO account for this client, the response is an empty array[].
Restrictions
Junior accounts have inherent restrictions that your integration should account for:
- No email-based login -- Juniors cannot log in with an email address. Only the alphanumeric username is accepted.
- Guardian dependency -- All critical communications (password reset, verification) are routed through the guardian's email if the junior does not have their own email.
- Forgot password -- When a junior triggers a password reset, the reset email is sent to the guardian's email (or the junior's own email if one is set). The junior uses their username to initiate the flow.
- Third-party integrations -- Some external integrations may not support minor accounts. Your application should check for the
minor_idclaim in the JWT and handle these cases gracefully (e.g. displaying a message that a feature is unavailable for junior accounts).
Profile
Junior accounts interact with the profile service in the same way as adult accounts. Juniors can update their profile, and their profile data (including date of birth) is used for the age-based upgrade check.
When a junior upgrades to an adult account, the profile service is notified and updates the profile to reflect the new account type and email address.
Summary
| Aspect | Adult Account | Junior Account |
|---|---|---|
| Login identifier | Email address | Alphanumeric username |
| Guardian required | No | Yes |
JWT minor_id claim | Absent | Present |
ROLE_GUARDIANVERIFIED_* | N/A | Assigned after guardian verification |
| Can upgrade | N/A | Yes, once age threshold is met |
| Password reset | Sent to user's email | Sent to guardian's email (or junior's own email) |
Updated 27 days ago
