Doc identity
Agach identity system: authentication (JWT, bcrypt), SSO/OIDC, teams, users, nodes, daemon onboarding, token managementFrom its SKILL.md
npx -y skills add JLugagne/agach --skill doc-identityAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 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.
SKILL.md
6.2 KB, ~1.6k tokens by cl100k_base, as published. Nobody here has run it
Agach Identity System (internal/identity/)
Overview
Authentication, authorization, SSO, team management, and daemon node onboarding.
Domain Types
Core (domain/types.go)
UserID,TeamID— UUID-based identifiersMemberRole— "admin" or "member"Team— ID, Name, Slug, Description, timestampsUser— ID, Email, DisplayName, PasswordHash, SSOProvider, SSOSubject, Role, TeamID, timestampsActor— UserID, Email, Role +IsAdmin()method (request-scoped auth context)DaemonActor— NodeID, OwnerUserID, Mode +IsZero()method
Nodes (domain/node.go)
NodeID,OnboardingCodeID— UUID-based identifiersNodeMode— "default" or "shared"NodeStatus— "active" or "revoked"Node— ID, OwnerUserID, Name, Mode, Status, RefreshTokenHash, LastSeenAt, RevokedAt, timestampsOnboardingCode— ID, Code (6-digit), CreatedByUserID, NodeMode, NodeName, ExpiresAt, UsedAt, UsedByNodeIDNodeAccess— ID, NodeID, UserID (nullable), TeamID (nullable)
SSO Config (domain/ssoconfig.go)
SsoProvider— Name, Icon, SAML (nullable), OIDC (nullable)OIDCConfig— IssuerURL, ClientID, ClientSecret, RedirectURL, ScopesSAMLConfig— MetadataURL, EntityID, ACSURL, Certificate (not yet supported)
Token TTLs (domain/ttl.go)
- DefaultRefreshTokenTTL = 7 days
- DefaultRememberMeTokenTTL = 30 days
- DefaultDaemonJWTTTL = 30 days
Errors (domain/errors.go)
ErrUnauthorized, ErrForbidden, ErrUserNotFound, ErrInvalidCredentials, ErrEmailAlreadyExists, ErrSSOUserNoPassword, ErrTeamNotFound, ErrTeamSlugConflict, ErrSSOProviderNotFound, ErrSSONotSupported, ErrNodeNotFound, ErrNodeRevoked, ErrOnboardingCodeNotFound/Expired/Used
Repository Interfaces
UserRepository— Create, FindByID, FindByEmail, FindBySSO, Update, ListAll, ListByTeamTeamRepository— Create, FindByID, FindBySlug, List, Update, DeleteNodeRepository— Create, FindByID, ListByOwner, ListActiveByOwner, Update, UpdateLastSeenOnboardingCodeRepository— Create, FindByCode, MarkUsed (FOR UPDATE lock), DeleteExpiredNodeAccessRepository— GrantUser/Team, RevokeUser/Team, ListByNode, HasAccess (ON CONFLICT DO NOTHING)
Service Interfaces
AuthCommands— Register, Login, LoginSSO, RefreshToken, Logout, UpdateProfile, ChangePassword, RefreshDaemonTokenAuthQueries— ValidateJWT, ValidateDaemonJWT, GetCurrentUserTeamCommands— CreateTeam, UpdateTeam, DeleteTeam, AddUserToTeam, RemoveUserFromTeam, SetUserRoleTeamQueries— ListTeams, GetTeam, ListUsers, ListTeamMembersOnboardingCommands— GenerateCode, CompleteOnboardingNodeCommands— RevokeNode, UpdateNodeAccess, RenameNodeNodeQueries— ListNodes, GetNode
App Layer
Auth (app/auth.go)
- bcrypt cost 12, min password 8 chars, min secret 32 bytes
- Access token TTL: 15 minutes
- Refresh token: 7 days (30 days with remember_me)
- JWT claims: sub, email, role, token_type, iat, exp
- Daemon JWT claims: sub (nodeID), owner_id, mode, token_type
SSO (app/sso.go)
- OIDC only (SAML not yet supported)
- Full flow: discovery → code exchange → JWK fetch → ID token validation
- RSA + ECDSA (P-256/P-384/P-521) key support
- Auto-creates user on first SSO login
Teams (app/teams.go)
- All mutations require
actor.IsAdmin()
Onboarding (app/onboarding.go)
- 6-digit numeric codes with uniqueness retries (3 attempts)
- 15-minute code expiry
- Refresh token: 32 random bytes, bcrypt hashed (cost 12)
Nodes (app/nodes.go)
- All mutations require node ownership (node.OwnerUserID == actor.UserID)
- UpdateNodeAccess requires NodeModeShared
HTTP Routes
Auth (rate limited: 5 requests / 15 minutes per IP)
POST /api/auth/register — Register new user
POST /api/auth/login — Login (email/password, remember_me)
POST /api/auth/refresh — Refresh access token (refresh_token cookie)
POST /api/auth/logout — Clear refresh_token cookie
GET /api/auth/me — Get current user
PATCH /api/auth/me — Update display name
POST /api/auth/me/password — Change password
SSO
GET /api/auth/sso/providers — List configured providers
GET /api/auth/sso/{provider}/authorize — OIDC authorization initiation
GET /api/auth/sso/{provider}/callback — OIDC callback (returns #sso_token=...)
Teams
GET /api/identity/teams — List teams
POST /api/identity/teams — Create team (admin)
DELETE /api/identity/teams/{id} — Delete team (admin)
GET /api/identity/users — List users (admins see emails)
PUT /api/identity/users/{id}/team — Add user to team (admin)
DELETE /api/identity/users/{id}/team — Remove from team (admin)
PUT /api/identity/users/{id}/role — Set user role (admin)
Onboarding & Nodes
POST /api/onboarding/codes — Generate onboarding code (auth required)
POST /api/onboarding/complete — Complete onboarding (unauthenticated)
POST /api/daemon/refresh — Refresh daemon token (unauthenticated)
GET /api/nodes — List nodes (auth required)
GET /api/nodes/{id} — Get node (ownership required)
DELETE /api/nodes/{id} — Revoke node (ownership required)
PATCH /api/nodes/{id}/name — Rename node
PUT /api/nodes/{id}/access — Update access grants (shared mode only)
Security
- Bcrypt password hashing (cost 12)
- HMAC-SHA256 JWT signing (≥ 32 byte secret)
- pgp_sym_encrypt for sensitive DB columns (password_hash, sso_subject)
- HttpOnly, Secure, SameSite=Strict cookies
- OIDC state verification with HMAC signatures
- Default admin seeded on first run: [email protected] / admin (env overridable)
Init Wiring (init.go)
- Create repositories (runs migrations)
- Create SSOService if providers configured
- Wire auth service (with/without nodes)
- Wire team, onboarding, node services
- Seed default admin if no users exist
- Return System struct with all services
What ships with it
Read from the repository
Just SKILL.md. No reference files, no scripts.