Skip to content
Back to skills

Moai Security Identity Majiayu000

ASecurity

Enterprise Skill for advanced development

  • 57 stars
  • 0 votes
  • 0 copies
  • 2 views
  • Added May 31, 2026
securityjavascriptrustgojavabashnodeexpressapidatabasebackend

Works with

  • cli
  • api
  • mcp

Security analysis

A100/100

Scanned May 31, 2026

npx -y skills add diegosouzapw/awesome-omni-skill --skill moai-security-identity --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Moai Security Identity Majiayu000?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Moai Security Identity Majiayu000
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/diegosouzapw-moai-security-identity-majiayu000/badge)](https://www.skillsdirectory.com/skills/diegosouzapw-moai-security-identity-majiayu000)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: "moai-security-identity"
version: "4.0.0"
status: stable
description: "Enterprise Skill for advanced development"
allowed-tools: "Read, Bash, WebSearch, WebFetch"
---

# moai-security-identity: SAML 2.0 & OIDC Identity Management

**Enterprise SSO with SAML 2.0, OpenID Connect & OAuth 2.0**  
Trust Score: 9.9/10 | Version: 4.0.0 | Enterprise Mode | Last Updated: 2025-11-12

---

## Overview

Identity and Access Management (IAM) for enterprise applications using SAML 2.0 for legacy systems and OpenID Connect (OIDC) for modern APIs. 2025 trend: 72% of enterprises now adopt multi-protocol SSO. This Skill covers SAML assertion validation, OIDC token processing, JWT verification, JIT provisioning, and SCIM 2.0 user synchronization.

**When to use this Skill:**
- Implementing enterprise Single Sign-On (SSO)
- Supporting multiple identity protocols (SAML + OIDC)
- Integrating Auth0, Keycloak, or Okta
- SAML/OIDC federation between organizations
- User provisioning automation (SCIM)
- Legacy B2B SAML + modern API OIDC

---

## Level 1: Foundations

### SAML vs OIDC Comparison

```
SAML 2.0 (XML-based, legacy enterprise):
├─ Protocol: XML assertions over HTTP POST/Redirect
├─ Use: Legacy web applications, B2B federation
├─ Complexity: Higher (XML parsing, certificates)
├─ Token Format: SAML Assertions (XML)
└─ Adoption: Enterprise (Salesforce, SharePoint, SAP)

OIDC (JSON-based, modern APIs):
├─ Protocol: Built on OAuth 2.0, REST APIs
├─ Use: Modern web/mobile apps, microservices
├─ Complexity: Lower (JSON, standard OAuth)
├─ Token Format: JWT (JSON Web Tokens)
└─ Adoption: Modern (mobile, SPA, APIs)

Best Practice (2025):
- Legacy B2B apps: SAML 2.0
- Modern APIs: OIDC
- Hybrid enterprises: Both (via federation)
```

### SAML 2.0 Flow

```
1. User clicks "Login with Company SSO"
   ↓
2. Service Provider (SP) → Identity Provider (IdP)
   Sends: AuthnRequest (signed, encrypted)
   ↓
3. User authenticates at IdP (username/password)
   ↓
4. IdP → Service Provider (SAML Response)
   Contains: SAML Assertion (signed, encrypted)
   ├─ NameID (user identifier)
   ├─ Attributes (email, groups, roles)
   └─ AuthnStatement (authentication confirmation)
   ↓
5. SP verifies signature, creates session
   ↓
6. User logged in to SP
```

### OIDC Flow

```
1. User clicks "Login with Google"
   ↓
2. SPA → Authorization Server
   Sends: authorization request (client_id, redirect_uri)
   ↓
3. User authenticates at Authorization Server
   ↓
4. Authorization Server → SPA (authorization code)
   ↓
5. SPA backend → Authorization Server (token exchange)
   Sends: authorization code, client_secret
   ↓
6. Authorization Server → SPA backend
   Returns: ID Token (JWT), Access Token, Refresh Token
   ↓
7. SPA backend creates session, user logged in
```

---

## Level 2: Implementation Patterns

### Pattern 1: SAML 2.0 Assertion Validation

```javascript
const passport = require('passport');
const { Strategy } = require('@node-saml/passport-saml');
const fs = require('fs');

const samlStrategy = new Strategy(
  {
    // Service Provider (our app) metadata
    entryPoint: 'https://idp.example.com/sso',  // IdP's SSO endpoint
    issuer: 'https://ourapp.com',
    callbackURL: 'https://ourapp.com/auth/saml/callback',
    
    // Certificates for signature verification
    cert: fs.readFileSync('./certs/idp-public.pem', 'utf-8'),
    
    // Security settings
    validateInResponseTo: true,
    wantAssertionsSigned: true,  // Require signed assertions
    wantAuthnResponseSigned: true,  // Require signed response
    
    // Encryption
    decryptionPvk: fs.readFileSync('./certs/sp-private.pem', 'utf-8'),
    
    // Identifier format
    identifierFormat: 'urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress',
  },
  (profile, done) => {
    // profile contains:
    // - nameID: unique user identifier
    // - nameIDFormat: format of identifier
    // - sessionIndex: session index
    // - attributes: user attributes from IdP
    
    console.log('SAML Profile:', profile);
    
    // Find or create user
    const user = {
      id: profile.nameID,
      email: profile.attributes.email,
      name: profile.attributes.displayName,
      groups: profile.attributes.groups || [],
    };
    
    done(null, user);
  }
);

passport.use('saml', samlStrategy);

// Express routes
app.get('/auth/saml', passport.authenticate('saml', {
  failureRedirect: '/login',
}));

app.post('/auth/saml/callback', (req, res, next) => {
  passport.authenticate('saml', (err, user) => {
    if (err || !user) {
      return res.redirect('/login?error=authentication_failed');
    }
    
    // Create session
    req.logIn(user, (err) => {
      if (err) return next(err);
      res.redirect('/dashboard');
    });
  })(req, res, next);
});

app.get('/auth/saml/metadata', (req, res) => {
  // Provide SP metadata for IdP to consume
  const metadata = samlStrategy.generateServiceProviderMetadata(
    null,  // decryption certificate
    null   // encryption certificate
  );
  
  res.type('application/xml').send(metadata);
});

// Logout (SAML SLO)
app.get('/logout', (req, res) => {
  if (!req.user) {
    return res.redirect('/');
  }
  
  const options = {
    destination: 'https://idp.example.com/slo',  // IdP's SLO endpoint
    issuer: 'https://ourapp.com',
  };
  
  samlStrategy.logout(req, (err, url) => {
    if (err) return res.status(500).send(err);
    
    req.logOut((err) => {
      if (err) return res.status(500).send(err);
      res.redirect(url);
    });
  });
});
```

### Pattern 2: OIDC Token Validation

```javascript
const { Issuer } = require('openid-client');
const jwt = require('jsonwebtoken');

class OIDCValidator {
  constructor(config) {
    this.config = config;
    this.issuer = null;
    this.client = null;
    this.jwks = null;
  }
  
  async initialize() {
    // Discover OIDC provider configuration
    this.issuer = await Issuer.discover(this.config.issuerUrl);
    
    // Create client
    this.client = new this.issuer.Client({
      client_id: this.config.clientId,
      client_secret: this.config.clientSecret,
      redirect_uris: [this.config.redirectUri],
      response_types: ['code'],
    });
    
    // Cache JWKS (JSON Web Key Set)
    const response = await fetch(`${this.config.issuerUrl}/.well-known/jwks.json`);
    this.jwks = await response.json();
  }
  
  // Validate ID Token signature
  validateIdToken(idToken) {
    const decoded = jwt.decode(idToken, { complete: true });
    
    if (!decoded) {
      throw new Error('Invalid token format');
    }
    
    const { header, payload } = decoded;
    
    // 1. Find public key matching kid
    const jwk = this.jwks.keys.find(key => key.kid === header.kid);
    if (!jwk) {
      throw new Error('Key not found in JWKS');
    }
    
    // 2. Convert JWK to PEM
    const publicKey = this.jwkToPem(jwk);
    
    // 3. Verify signature
    try {
      const verified = jwt.verify(idToken, publicKey, {
        algorithms: ['RS256'],  // Ensure RS256
        issuer: this.config.issuerUrl,
        audience: this.config.clientId,
      });
      
      return verified;
    } catch (error) {
      throw new Error(`Token verification failed: ${error.message}`);
    }
  }
  
  // Validate Access Token
  validateAccessToken(accessToken) {
    const decoded = jwt.decode(accessToken, { complete: true });
    
    if (!decoded) {
      throw new Error('Invalid token format');
    }
    
    // 1. Check expiration
    const { payload } = decoded;
    const now = Math.floor(Date.now() / 1000);
    
    if (payload.exp <= now) {
      throw new Error('Token expired');
    }
    
    // 2. Check issuer
    if (payload.iss !== this.config.issuerUrl) {
      throw new Error('Invalid issuer');
    }
    
    return payload;
  }
  
  // Convert JWK to PEM format
  jwkToPem(jwk) {
    // Implementation using node-jose or similar
    // Returns PEM-formatted public key
    // ... (crypto conversion logic)
  }
}

// Usage
const oidcValidator = new OIDCValidator({
  issuerUrl: 'https://auth.example.com',
  clientId: 'my-app-id',
  clientSecret: 'my-secret',
  redirectUri: 'https://myapp.com/auth/callback',
});

await oidcValidator.initialize();

// In middleware
app.use((req, res, next) => {
  const authHeader = req.headers.authorization;
  if (!authHeader) {
    return res.status(401).json({ error: 'Missing authorization' });
  }
  
  const token = authHeader.replace('Bearer ', '');
  
  try {
    req.user = oidcValidator.validateIdToken(token);
    next();
  } catch (error) {
    res.status(401).json({ error: error.message });
  }
});
```

### Pattern 3: SCIM 2.0 User Provisioning

```javascript
class SCIMUserProvisioner {
  constructor(config) {
    this.config = config;
  }
  
  // Handle SCIM provisioning webhook from IdP
  handleScimWebhook(scimEvent) {
    switch (scimEvent.resourceType) {
      case 'User':
        return this.handleUserEvent(scimEvent);
      case 'Group':
        return this.handleGroupEvent(scimEvent);
      default:
        throw new Error(`Unknown resource type: ${scimEvent.resourceType}`);
    }
  }
  
  async handleUserEvent(event) {
    const { externalId, attributes } = event;
    
    switch (event.eventType) {
      case 'user.created':
        return this.createUser(attributes);
      
      case 'user.updated':
        return this.updateUser(externalId, attributes);
      
      case 'user.deleted':
        return this.deleteUser(externalId);
      
      default:
        throw new Error(`Unknown event: ${event.eventType}`);
    }
  }
  
  async createUser(attributes) {
    // Validate required fields
    if (!attributes.email || !attributes.userName) {
      throw new Error('Missing required fields');
    }
    
    // Create database record
    const user = await db.users.create({
      externalId: attributes.externalId,
      email: attributes.email,
      displayName: attributes.displayName,
      givenName: attributes.givenName,
      familyName: attributes.familyName,
      active: attributes.active ?? true,
      groups: attributes.groups || [],
    });
    
    return user;
  }
  
  async updateUser(externalId, attributes) {
    const user = await db.users.findByExternalId(externalId);
    
    if (!user) {
      throw new Error(`User not found: ${externalId}`);
    }
    
    // Update fields
    const updated = await db.users.update(user.id, {
      displayName: attributes.displayName,
      active: attributes.active,
      groups: attributes.groups || [],
    });
    
    return updated;
  }
  
  async deleteUser(externalId) {
    const user = await db.users.findByExternalId(externalId);
    
    if (!user) {
      throw new Error(`User not found: ${externalId}`);
    }
    
    // Soft delete (mark as inactive)
    await db.users.update(user.id, { active: false });
    
    return { success: true };
  }
  
  async handleGroupEvent(event) {
    // Similar pattern for group provisioning
    // Handle group.created, group.updated, group.deleted
  }
}

// Express endpoint for SCIM webhooks
app.post('/scim/webhook', async (req, res) => {
  try {
    // Verify webhook signature
    if (!verifyWebhookSignature(req)) {
      return res.status(401).json({ error: 'Invalid signature' });
    }
    
    const provisioner = new SCIMUserProvisioner(config);
    const result = await provisioner.handleScimWebhook(req.body);
    
    res.json(result);
  } catch (error) {
    console.error('SCIM webhook error:', error);
    res.status(400).json({ error: error.message });
  }
});
```

### Pattern 4: JWT Bearer Token in APIs

```javascript
class JWTMiddleware {
  constructor(publicKey) {
    this.publicKey = publicKey;
  }
  
  middleware() {
    return (req, res, next) => {
      const authHeader = req.headers.authorization;
      
      if (!authHeader || !authHeader.startsWith('Bearer ')) {
        return res.status(401).json({ error: 'Missing token' });
      }
      
      const token = authHeader.slice(7);  // Remove "Bearer "
      
      try {
        const payload = jwt.verify(token, this.publicKey, {
          algorithms: ['RS256'],
        });
        
        req.user = {
          id: payload.sub,
          email: payload.email,
          scope: payload.scope ? payload.scope.split(' ') : [],
        };
        
        next();
      } catch (error) {
        res.status(401).json({ error: 'Invalid token' });
      }
    };
  }
}

// Usage
const jwtMiddleware = new JWTMiddleware(publicKey);
app.use('/api', jwtMiddleware.middleware());

app.get('/api/protected', (req, res) => {
  res.json({
    message: `Hello, ${req.user.email}`,
    scopes: req.user.scope,
  });
});
```

---

## Level 3: Advanced

### Advanced: Context7 MCP Integration

```javascript
const { Context7Client } = require('context7-mcp');

class IdentityThreatIntelligence {
  constructor(apiKey) {
    this.context7 = new Context7Client(apiKey);
  }
  
  // Check user identity against threat intelligence
  async validateUserIdentity(user) {
    const threats = await this.context7.query({
      type: 'identity_threat',
      email: user.email,
      externalId: user.externalId,
      tags: ['fraud', 'compromise', 'insider_threat'],
    });
    
    return {
      safe: threats.severity === 0,
      severity: threats.severity,
      details: threats,
    };
  }
  
  // Monitor provisioning events for anomalies
  async analyzeProvisioningEvent(event) {
    const analysis = await this.context7.query({
      type: 'provisioning_anomaly',
      eventType: event.eventType,
      timestamp: event.timestamp,
      userId: event.externalId,
    });
    
    if (analysis.anomalous) {
      console.warn('Anomalous provisioning event detected:', analysis);
      // Alert security team
    }
    
    return analysis;
  }
}
```

---

## Checklist

- [ ] SAML 2.0 strategy configured with certificate verification
- [ ] OIDC provider discovery working
- [ ] JWT token signature validation implemented
- [ ] Token expiration checks in place
- [ ] SCIM webhook handling for user provisioning
- [ ] JIT (Just-In-Time) provisioning working
- [ ] Multi-protocol SSO (SAML + OIDC) tested
- [ ] Identity threat intelligence integrated
- [ ] SSO logout (SLO) working
- [ ] Performance tested at scale

---

## Quick Reference

| Feature | Implementation |
|---------|-----------------|
| SAML | @node-saml/passport-saml 3.2.4+ |
| OIDC | openid-client (npm) |
| JWT | jsonwebtoken (npm) |
| SCIM | Custom webhook handler |
| Monitoring | Context7 MCP |

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.