Skip to content

Quick Reference

Essential Information

Base URLs

  • Production: https://engagifii-identity-live.azurewebsites.net
  • QA/Staging: https://engagifii-qa-identity.azurewebsites.net
  • Development: https://engagifii-dev-identity.azurewebsites.net

Key Endpoints

Authorization: /connect/authorize
Token:        /connect/token
UserInfo:     /connect/userinfo
Logout:       /connect/endsession
Discovery:    /.well-known/openid-configuration
JWKS:         /.well-known/openid-configuration/jwks

Common Scopes

  • openid - OpenID Connect identity
  • profile - User profile information
  • email - Email address
  • offline_access - Refresh tokens
  • api - API access

Quick Start Examples

Web Application Login

javascript
// 1. Redirect to login
window.location.href = 
  'https://engagifii-identity-live.azurewebsites.net/connect/authorize?' +
  'client_id=YOUR_CLIENT_ID&' +
  'response_type=code&' +
  'redirect_uri=https://yourapp.com/callback&' +
  'scope=openid profile email';

// 2. Handle callback and exchange code
const code = new URLSearchParams(window.location.search).get('code');

const tokenResponse = await fetch('https://engagifii-identity-live.azurewebsites.net/connect/token', {
  method: 'POST',
  headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
  body: new URLSearchParams({
    grant_type: 'authorization_code',
    code: code,
    redirect_uri: 'https://yourapp.com/callback',
    client_id: 'YOUR_CLIENT_ID',
    client_secret: 'YOUR_CLIENT_SECRET'
  })
});

const tokens = await tokenResponse.json();

Service-to-Service Authentication

javascript
// Get access token for API calls
const response = await fetch('https://engagifii-identity-live.azurewebsites.net/connect/token', {
  method: 'POST',
  headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
  body: new URLSearchParams({
    grant_type: 'client_credentials',
    client_id: 'SERVICE_CLIENT_ID',
    client_secret: 'SERVICE_CLIENT_SECRET',
    scope: 'api.read api.write'
  })
});

const { access_token } = await response.json();

SPA with PKCE

javascript
// Generate PKCE challenge
const codeVerifier = generateRandomString(128);
const codeChallenge = await sha256(codeVerifier);

// 1. Authorization request
window.location.href = 
  'https://engagifii-identity-live.azurewebsites.net/connect/authorize?' +
  'client_id=SPA_CLIENT_ID&' +
  'response_type=code&' +
  'redirect_uri=https://spa.com/callback&' +
  'scope=openid profile api&' +
  'code_challenge=' + codeChallenge + '&' +
  'code_challenge_method=S256';

// 2. Token exchange (no client secret)
const tokens = await fetch('https://engagifii-identity-live.azurewebsites.net/connect/token', {
  method: 'POST',
  headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
  body: new URLSearchParams({
    grant_type: 'authorization_code',
    code: authCode,
    redirect_uri: 'https://spa.com/callback',
    client_id: 'SPA_CLIENT_ID',
    code_verifier: codeVerifier
  })
});

Common Operations

Get User Information

javascript
const userInfo = await fetch('https://engagifii-identity-live.azurewebsites.net/connect/userinfo', {
  headers: {
    'Authorization': `Bearer ${access_token}`
  }
});

const user = await userInfo.json();
// Returns: { sub, name, email, ... }

Refresh Access Token

javascript
const response = await fetch('https://engagifii-identity-live.azurewebsites.net/connect/token', {
  method: 'POST',
  headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
  body: new URLSearchParams({
    grant_type: 'refresh_token',
    refresh_token: 'YOUR_REFRESH_TOKEN',
    client_id: 'YOUR_CLIENT_ID',
    client_secret: 'YOUR_CLIENT_SECRET'
  })
});

const newTokens = await response.json();

Logout

javascript
// Redirect to logout
window.location.href = 
  'https://engagifii-identity-live.azurewebsites.net/connect/endsession?' +
  'id_token_hint=' + idToken + '&' +
  'post_logout_redirect_uri=https://yourapp.com';

Validate Token (Introspection)

javascript
const response = await fetch('https://engagifii-identity-live.azurewebsites.net/connect/introspect', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/x-www-form-urlencoded',
    'Authorization': 'Basic ' + btoa(client_id + ':' + client_secret)
  },
  body: new URLSearchParams({
    token: access_token
  })
});

const tokenInfo = await response.json();
// Returns: { active: true/false, scope, exp, ... }

Token Formats

Access Token Claims

json
{
  "iss": "https://engagifii-identity-live.azurewebsites.net",
  "aud": ["api1", "api2"],
  "client_id": "webapp",
  "sub": "user123",
  "scope": ["openid", "profile", "api"],
  "exp": 1672531200,
  "iat": 1672527600
}

ID Token Claims

json
{
  "iss": "https://engagifii-identity-live.azurewebsites.net",
  "aud": "webapp",
  "sub": "user123",
  "name": "John Doe",
  "email": "john@example.com",
  "email_verified": true,
  "iat": 1672527600,
  "exp": 1672531200
}

Error Quick Reference

Error CodeMeaningQuick Fix
invalid_clientWrong credentialsCheck client_id and secret
invalid_grantCode/token expiredRequest new authorization
invalid_scopeScope not allowedUse configured scopes
invalid_requestMissing parameterCheck required params
access_deniedUser deniedHandle in UI gracefully
invalid_tokenToken expired/invalidRefresh or re-authenticate

HTTP Status Codes

CodeMeaningAction
200SuccessProcess response
302RedirectFollow redirect
400Bad requestFix parameters
401UnauthorizedAuthenticate
429Rate limitedWait and retry
500Server errorRetry with backoff

Security Checklist

  • [ ] Always use HTTPS
  • [ ] Store secrets securely (never client-side)
  • [ ] Validate state parameter
  • [ ] Use PKCE for public clients
  • [ ] Implement token refresh
  • [ ] Handle token expiry
  • [ ] Validate ID token signature
  • [ ] Implement proper logout

Integration Patterns

Token Management Class

javascript
class TokenManager {
  constructor(clientId, clientSecret) {
    this.clientId = clientId;
    this.clientSecret = clientSecret;
    this.tokens = null;
  }

  async getAccessToken() {
    if (!this.tokens || this.isExpired()) {
      await this.refresh();
    }
    return this.tokens.access_token;
  }

  isExpired() {
    return Date.now() >= (this.tokens.expires_at - 300000);
  }

  async refresh() {
    // Implement token refresh logic
  }
}

API Request Wrapper

javascript
async function apiRequest(endpoint, options = {}) {
  const token = await tokenManager.getAccessToken();
  
  const response = await fetch(endpoint, {
    ...options,
    headers: {
      ...options.headers,
      'Authorization': `Bearer ${token}`
    }
  });

  if (response.status === 401) {
    // Token expired, refresh and retry
    await tokenManager.refresh();
    return apiRequest(endpoint, options);
  }

  return response;
}

Express Middleware

javascript
function requireAuth(req, res, next) {
  if (!req.session?.tokens?.access_token) {
    return res.redirect('/login');
  }
  
  const expiresAt = req.session.tokens.expires_at;
  if (Date.now() >= expiresAt) {
    return res.redirect('/login');
  }
  
  next();
}

Testing Tools

cURL Examples

bash
# Get access token (client credentials)
curl -X POST https://engagifii-identity-live.azurewebsites.net/connect/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=client_credentials&client_id=CLIENT_ID&client_secret=SECRET&scope=api"

# Get user info
curl -X GET https://engagifii-identity-live.azurewebsites.net/connect/userinfo \
  -H "Authorization: Bearer ACCESS_TOKEN"

# Introspect token
curl -X POST https://engagifii-identity-live.azurewebsites.net/connect/introspect \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -u "CLIENT_ID:CLIENT_SECRET" \
  -d "token=ACCESS_TOKEN"

Postman Environment Variables

json
{
  "identity_url": "https://engagifii-identity-live.azurewebsites.net",
  "client_id": "your-client-id",
  "client_secret": "your-client-secret",
  "redirect_uri": "https://oauth.pstmn.io/v1/callback",
  "scope": "openid profile email api",
  "access_token": "{{auto-populated}}",
  "refresh_token": "{{auto-populated}}"
}

Debugging Commands

Decode JWT (bash)

bash
echo "JWT_TOKEN" | cut -d. -f2 | base64 -d | jq

Decode JWT (JavaScript)

javascript
const decoded = JSON.parse(atob(token.split('.')[1]));
console.log(decoded);

Check Token Expiry

javascript
const payload = JSON.parse(atob(token.split('.')[1]));
const expiresAt = new Date(payload.exp * 1000);
console.log('Token expires at:', expiresAt);
console.log('Is expired:', Date.now() > payload.exp * 1000);

Environment Variables

Required Configuration

bash
# Identity Service
IDENTITY_URL=https://engagifii-identity-live.azurewebsites.net
CLIENT_ID=your-client-id
CLIENT_SECRET=your-client-secret

# Application
REDIRECT_URI=https://yourapp.com/callback
POST_LOGOUT_URI=https://yourapp.com
SCOPES=openid profile email api

# Session
SESSION_SECRET=random-secret-string
SESSION_TIMEOUT=3600000

Rate Limits

EndpointLimitWindow
/connect/authorize10 reqPer minute
/connect/token20 reqPer minute
/connect/userinfo100 reqPer minute
/connect/introspect50 reqPer minute

Remember: Always use HTTPS, never expose secrets client-side, and implement proper error handling!