Fluxer supports OAuth2 for third-party application authorization, allowing users to grant limited access to their accounts without sharing credentials.
OAuth2 Scopes
Scopes define what resources an application can access:
export type OAuth2Scope =
| 'identify' // Basic user information
| 'email' // User email address
| 'guilds' // User's guilds
| 'connections' // User's connections
| 'bot' // Add bot to guilds
| 'admin' ; // Administrative access
Scope Descriptions
Basic user information Access to:
User ID
Username
Avatar
Discriminator
Public flags
{
"id" : "123456789" ,
"username" : "user" ,
"avatar" : "a_1234567890abcdef" ,
"discriminator" : "0001" ,
"public_flags" : 0
}
User email address Includes:
Email address
Verification status
User’s guilds Access to:
Guild list
Guild names
Guild icons
User’s permissions
[
{
"id" : "987654321" ,
"name" : "My Server" ,
"icon" : "1234567890abcdef" ,
"owner" : false ,
"permissions" : "2147483647"
}
]
User’s connected accounts Access to:
Connected services (GitHub, Twitter, etc.)
Connection metadata
[
{
"type" : "github" ,
"id" : "12345" ,
"name" : "username" ,
"verified" : true
}
]
Add bot to guilds Allows:
Adding the bot to guilds the user has MANAGE_GUILD permission in
Joining guilds via invite links
This scope is only valid for bot applications
Administrative access Full access to:
All user data
Administrative endpoints
Sensitive operations
This scope should only be granted to fully trusted applications
Authorization Flow
1. Authorization URL
Redirect users to the authorization endpoint:
import { authorizeUrl } from '@fluxer/oauth2' ;
const authUrl = authorizeUrl ({
clientId: 'YOUR_CLIENT_ID' ,
clientSecret: 'YOUR_CLIENT_SECRET' ,
redirectUri: 'https://yourapp.com/callback' ,
authorizeEndpoint: 'https://fluxer.app/oauth2/authorize' ,
tokenEndpoint: 'https://fluxer.app/api/oauth2/token' ,
scope: 'identify email guilds'
}, state );
// Redirect user to authUrl
window . location . href = authUrl ;
Authorization URL Format:
https://fluxer.app/oauth2/authorize?
response_type=code&
client_id=YOUR_CLIENT_ID&
redirect_uri=https://yourapp.com/callback&
scope=identify+email+guilds&
state=random_state_string
2. Authorization Grant
User approves the authorization request. Fluxer redirects to your redirect_uri:
https://yourapp.com/callback?code=AUTHORIZATION_CODE&state=random_state_string
3. Token Exchange
Exchange the authorization code for an access token:
const response = await fetch ( 'https://fluxer.app/api/oauth2/token' , {
method: 'POST' ,
headers: {
'Content-Type' : 'application/json' ,
},
body: JSON . stringify ({
grant_type: 'authorization_code' ,
code: 'AUTHORIZATION_CODE' ,
redirect_uri: 'https://yourapp.com/callback' ,
client_id: 'YOUR_CLIENT_ID' ,
client_secret: 'YOUR_CLIENT_SECRET'
})
});
const data = await response . json ();
Response:
{
"access_token" : "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." ,
"token_type" : "Bearer" ,
"expires_in" : 604800 ,
"refresh_token" : "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." ,
"scope" : "identify email guilds"
}
4. Accessing Resources
Use the access token to make API requests:
const response = await fetch ( 'https://fluxer.app/api/users/@me' , {
headers: {
'Authorization' : `Bearer ${ accessToken } `
}
});
const user = await response . json ();
Token Refresh
Access tokens expire after 7 days. Use the refresh token to obtain a new access token:
const response = await fetch ( 'https://fluxer.app/api/oauth2/token' , {
method: 'POST' ,
headers: {
'Content-Type' : 'application/json' ,
},
body: JSON . stringify ({
grant_type: 'refresh_token' ,
refresh_token: 'YOUR_REFRESH_TOKEN' ,
client_id: 'YOUR_CLIENT_ID' ,
client_secret: 'YOUR_CLIENT_SECRET'
})
});
const data = await response . json ();
Response:
{
"access_token" : "new_access_token" ,
"token_type" : "Bearer" ,
"expires_in" : 604800 ,
"refresh_token" : "new_refresh_token" ,
"scope" : "identify email guilds"
}
State Parameter
The state parameter prevents CSRF attacks:
import { generateState } from '@fluxer/oauth2' ;
// Generate random state
const state = generateState ();
// Store state in session
session . oauthState = state ;
// Include in authorization URL
const authUrl = authorizeUrl ( config , state );
// Verify state on callback
if ( req . query . state !== session . oauthState ) {
throw new Error ( 'Invalid state parameter' );
}
Error Handling
Authorization Errors
Fluxer redirects to your redirect_uri with error parameters:
https://yourapp.com/callback?
error=access_denied&
error_description=The+user+denied+access
Error Codes:
Code Description invalid_requestMissing or invalid parameters unauthorized_clientClient not authorized for this grant type access_deniedUser denied the authorization request unsupported_response_typeAuthorization server doesn’t support this response type invalid_scopeRequested scope is invalid or unknown server_errorInternal server error temporarily_unavailableAuthorization server is temporarily unavailable
Token Errors
{
"error" : "invalid_grant" ,
"error_description" : "Invalid authorization code"
}
HTTP Status: 400 Bad Request
Scope Validation
Validate that your token has required scopes:
function hasScope ( token : string , requiredScope : string ) : boolean {
const decoded = jwt . decode ( token );
const scopes = decoded . scope . split ( ' ' );
return scopes . includes ( requiredScope );
}
if ( ! hasScope ( accessToken , 'email' )) {
throw new Error ( 'Missing email scope' );
}
Rate Limits
OAuth2 endpoints have specific rate limits:
Endpoint Limit Window /oauth2/authorize10 10 seconds /oauth2/token10 10 seconds /oauth2/revoke10 10 seconds
See Rate Limiting for details.
Bot Applications
Bot Scope
Bot applications require the bot scope:
https://fluxer.app/oauth2/authorize?
response_type=code&
client_id=BOT_CLIENT_ID&
scope=bot&
permissions=8&
guild_id=123456789
Parameters:
Bitwise permission value to request (optional)
Pre-select a guild for the user (optional)
Bot tokens use a different format:
Use this in the Authorization header:
const response = await fetch ( 'https://fluxer.app/api/guilds/123456789' , {
headers: {
'Authorization' : `Bot ${ botToken } `
}
});
Security Best Practices
Never Expose Client Secret Keep your client secret secure. Never include it in client-side code or version control.
Validate State Parameter Always validate the state parameter to prevent CSRF attacks.
Use HTTPS Only use OAuth2 over HTTPS. Never send credentials over unencrypted connections.
Minimal Scopes Request only the scopes your application actually needs.
Token Storage Store tokens securely. Use encryption for sensitive storage (databases, cookies).
Token Rotation Rotate refresh tokens regularly and invalidate old tokens when new ones are issued.
OAuth2 Errors
Missing Scope Error
import { MissingOAuthScopeError } from '@fluxer/errors' ;
try {
// Attempt operation requiring 'email' scope
} catch ( error ) {
if ( error instanceof MissingOAuthScopeError ) {
console . log ( 'Missing required OAuth2 scope' );
}
}
API Response:
{
"code" : "MISSING_OAUTH_SCOPE" ,
"message" : "Missing required OAuth2 scope"
}
HTTP Status: 403 Forbidden
Client Credentials Flow
For server-to-server authentication:
const response = await fetch ( 'https://fluxer.app/api/oauth2/token' , {
method: 'POST' ,
headers: {
'Content-Type' : 'application/json' ,
},
body: JSON . stringify ({
grant_type: 'client_credentials' ,
client_id: 'YOUR_CLIENT_ID' ,
client_secret: 'YOUR_CLIENT_SECRET' ,
scope: 'bot'
})
});
Client credentials flow is typically used for bot applications making API requests without user context.