Cbsso
Collection of skills for the ColdBox Platform and Claude Plugin
npx -y skills add ColdBox/skills --skill cbssoAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
- 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Use this skill when implementing Single Sign-On (SSO) in ColdBox/BoxLang using the cbsso module. Covers SAML2 and OAuth2/OIDC configuration, the SSOService API, redirect-to-provider flow, callback processing, token validation, user provisioning on first login, and session management.
SKILL.md
6.0 KB, ~1.4k tokens by cl100k_base, as published. Nobody here has run it
CBSSO Skill
When to Use This Skill
Load this skill when:
- Integrating ColdBox applications with enterprise SSO providers (Okta, Azure AD, Auth0, Google)
- Implementing SAML2 or OAuth2/OIDC authentication flows
- Processing SSO callbacks and provisioning users on first login
- Managing federated identity sessions alongside cbsecurity
- Handling SSO logout (single logout)
Installation
box install cbsso
Configuration
config/modules/cbsso.cfc
function configure() {
return {
// SSO provider type: "saml2" | "oauth2" | "oidc"
provider : "oauth2",
oauth2 : {
clientId : getSystemSetting( "SSO_CLIENT_ID", "" ),
clientSecret : getSystemSetting( "SSO_CLIENT_SECRET", "" ),
authURL : getSystemSetting( "SSO_AUTH_URL", "" ),
tokenURL : getSystemSetting( "SSO_TOKEN_URL", "" ),
userInfoURL : getSystemSetting( "SSO_USERINFO_URL", "" ),
redirectURI : getSystemSetting( "SSO_REDIRECT_URI", "" ),
scopes : "openid profile email",
pkce : true // enable PKCE for public clients
},
// Where to send users after login
successRedirect : "dashboard",
// Where to send on SSO failure
failureRedirect : "security.login"
}
}
SAML2 Provider Configuration
saml2 : {
idpEntityId : getSystemSetting( "SAML_IDP_ENTITY_ID" ),
idpSSOURL : getSystemSetting( "SAML_IDP_SSO_URL" ),
idpCertificate : getSystemSetting( "SAML_IDP_CERT" ),
spEntityId : getSystemSetting( "SAML_SP_ENTITY_ID" ),
spACSURL : getSystemSetting( "SAML_SP_ACS_URL" ),
spPrivateKey : getSystemSetting( "SAML_SP_PRIVATE_KEY" ),
spCertificate : getSystemSetting( "SAML_SP_CERT" ),
nameIdFormat : "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress",
signRequests : true,
wantAssertionsSigned : true
}
Core API
Injection
property name="ssoService" inject="SSOService@cbsso";
Initiate SSO Login
// Redirect to identity provider
function ssoLogin( event, rc, prc ) {
var redirectURL = ssoService.getAuthorizationURL( {
state : createUUID() // store in session for CSRF check
} )
sessionStorage.set( "ssoState", state )
relocate( redirectURL )
}
Process Callback
function callback( event, rc, prc ) {
try {
// Validate state to prevent CSRF
if ( rc.state != sessionStorage.get( "ssoState" ) ) {
throw( type = "CSRFException", message = "Invalid SSO state" )
}
sessionStorage.delete( "ssoState" )
// Exchange code for tokens and get user claims
var claims = ssoService.processCallback( rc.code ?: "", rc.state ?: "" )
// Provision or retrieve user
var user = provisionUser( claims )
// Log user in via cbauth/cbsecurity
authService.login( user )
messagebox.success( "Signed in successfully via SSO." )
relocate( "dashboard" )
} catch ( CSRFException e ) {
messagebox.error( "Invalid SSO request." )
relocate( "security.login" )
} catch ( SSOException e ) {
log.error( "SSO callback failed: #e.message#" )
messagebox.error( "SSO authentication failed. Please try again." )
relocate( "security.login" )
}
}
User Provisioning (JIT Provisioning)
private function provisionUser( claims ) {
// Try to find existing user by SSO subject or email
var user = userService.findByEmail( claims.email ?: "" )
if ( isNull( user ) ) {
// Just-in-time provisioning — create user on first SSO login
user = userService.create( {
email : claims.email,
firstName : claims.given_name ?: "",
lastName : claims.family_name ?: "",
ssoProvider : "okta",
ssoSubject : claims.sub,
role : mapSSOGroupsToRole( claims.groups ?: [] ),
isActive : true
} )
} else {
// Update attributes that may have changed in the IdP
user.update( {
firstName : claims.given_name ?: user.getFirstName(),
lastName : claims.family_name ?: user.getLastName()
} )
}
return user
}
SSO Logout (Single Logout)
function logout( event, rc, prc ) {
authService.logout()
// Initiate SSO single logout if provider supports it
if ( ssoService.supportsLogout() ) {
relocate( ssoService.getLogoutURL() )
} else {
relocate( "security.login" )
}
}
Best Practices
- Store SSO credentials in environment variables — never commit
clientSecretor private keys - Validate OAuth state parameter on every callback — prevents CSRF attacks against the OAuth flow
- Enable PKCE for OAuth2 flows — mitigates authorization code interception attacks
- Use HTTPS for all redirect URIs — IdPs reject HTTP callback URLs in production
- Validate all received claims — do not trust unverified
emailorsubfrom untrusted sources - Provision users conservatively — only assign elevated roles after verifying group membership claims
- Store SSO subject alongside email — allows login after an email address change on the IdP
- Implement single logout where the provider supports it — prevents stale sessions on shared devices