{"id":28967567,"url":"https://github.com/su-sws/adapt-auth-sdk","last_synced_at":"2026-03-07T21:32:37.437Z","repository":{"id":41821869,"uuid":"439148471","full_name":"SU-SWS/adapt-auth-sdk","owner":"SU-SWS","description":"Connect style middleware for SAML authentication with ADAPT SSO SP and IDCS IDP","archived":false,"fork":false,"pushed_at":"2025-05-29T05:31:03.000Z","size":576,"stargazers_count":0,"open_issues_count":6,"forks_count":0,"subscribers_count":13,"default_branch":"main","last_synced_at":"2025-06-24T08:09:23.264Z","etag":null,"topics":["adapt","node","passportjs","saml2"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":false,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/SU-SWS.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-12-16T22:55:16.000Z","updated_at":"2022-01-18T19:16:11.000Z","dependencies_parsed_at":"2024-01-29T20:13:03.240Z","dependency_job_id":"44b9d314-30b0-40f8-a9a3-da76d453638e","html_url":"https://github.com/SU-SWS/adapt-auth-sdk","commit_stats":{"total_commits":49,"total_committers":6,"mean_commits":8.166666666666666,"dds":0.5714285714285714,"last_synced_commit":"446ce033b1975af9ea9609924d98cd36c4e10346"},"previous_names":[],"tags_count":21,"template":false,"template_full_name":null,"purl":"pkg:github/SU-SWS/adapt-auth-sdk","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SU-SWS%2Fadapt-auth-sdk","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SU-SWS%2Fadapt-auth-sdk/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SU-SWS%2Fadapt-auth-sdk/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SU-SWS%2Fadapt-auth-sdk/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/SU-SWS","download_url":"https://codeload.github.com/SU-SWS/adapt-auth-sdk/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SU-SWS%2Fadapt-auth-sdk/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":261632137,"owners_count":23187273,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["adapt","node","passportjs","saml2"],"created_at":"2025-06-24T08:09:24.157Z","updated_at":"2026-03-07T21:32:37.377Z","avatar_url":"https://github.com/SU-SWS.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Adapt Auth SDK\n\nThe AdaptAuth SDK provides all the functionality to easily integrate your Javascript\nweb applications with our Stanford SAML federated identity provider. \n\n## Usage\n\nThe AdaptAuth SDK is intended to be used in node [connect](https://github.com/senchalabs/connect)\nstyle http server middleware (e.g. [express](https://expressjs.com/)).\nTo use it just configure your env, import the SDK client, and use the middlewares in your app.\n\n```typescript\nimport express from 'express';\nimport { auth } from 'AdaptAuth';\n\nconst app = express();\n\n// Add AdaptAuth authorization middleware\napp.use(auth.authorize());\napp.get('/my-protected-endpoint', (req, res) =\u003e {\n  // Nothing to see here...\n});\n\n\napp.listen(3000);\n```\n\n### Configuration\nThe easiest way to configure AdaptAuth is by setting environment variables\n```bash\n# adapt-sso-sp SAML service provider login url (REQUIRED)\nADAPT_AUTH_SAML_SP_URL=\"https://adapt-sso-uat.stanford.edu/api/sso/login\"\n# adapt-sso-sp SAML registry entity id (REQUIRED)\nADAPT_AUTH_SAML_ENTITY=\"my-saml-app-entity\"\n# SAML signing pem certificate (REQUIRED)\nADAPT_AUTH_SAML_CERT=\"PEM used for saml document signing\"\n# Private key used to decrypt encrypted SAML assertions (optional)\nADAPT_AUTH_SAML_DECRYPTION_KEY=\"private decryption key\"\n# Local app origin part for SAML returnTo POST back\nADAPT_AUTH_SAML_RETURN_ORIGIN=\"https://my-app.stanford.edu\"\n# Local app path part for SAML returnTo POST back\nADAPT_AUTH_SAML_RETURN_PATH=\"/auth/saml\"\n# Local app endpoint to handle SAML POST back (overrides host/path when set)\n# ADAPT_AUTH_SAML_RETURN_URL=\"https://my-app.stanford.edu/auth/saml\"\n# Secret used for signing/verifying local session jwts (REQUIRED)\nADAPT_AUTH_SESSION_SECRET=\"some-signing-secret\"\n# Name for local session cookie (optional)\nADAPT_AUTH_SESSION_NAME=\"adapt-auth\"\n# expiresIn / maxAge for session tokens\nADAPT_AUTH_SESSION_EXPIRES_IN=\"24h\"\n# Local url to redirect to after logging out of session (optional) defaults to \"/\"\nADAPT_AUTH_SESSION_LOGOUT_URL=\"/login\"\n# Local url to redirect to after authorize middleware failure (optional) defaults to responding 401\nADAPT_AUTH_SESSION_UNAUTHORIZED_URL\n```\n\nYou can optionally instantiate a new AdaptAuth instance and pass your own configuration values.\n```typescript\nimport { AdaptAuth } from 'AdaptAuth';\n\nconst myAuthInstance = new AdaptAuth({\n  saml: {\n    serviceProviderLoginUrl: 'https://adapt-sso.stanford.edu/api/sso/login',\n    entity: 'my-other-saml-entity',\n    returnToHost: process.env.APP_HOST,\n    returnToPath: '/auth/saml'\n    cert: 'MySamlCert',\n  },\n  session: {\n    name: 'my-auth-session',\n    secret: 'my-jwt-secret',\n    logoutRedirectUrl: '/login',\n    unauthorizedRedirectUrl: '/login?code=UNAUTHORIZED',\n  },\n});\n\n...\n```\n\n## Basic Auth Flow Integration\n\nA basic usage of this SDK would involve the following endpoints setup:\n- Using `auth.initiate` to redirect users to the SAML service provider\n- Using `auth.authenticate` to handle the SAML document POST back from the IdP and create a local session\n- Using `auth.authorize` on protected endpoints/routes to verify valid local sessions\n- Using `auth.destroySession` to provide an additional way for a user to manually end their session\n\nHere's an example express app:\n```typescript\nimport express from 'express';\nimport cookieParser from 'cookie-parser';\nimport { auth } from 'AdaptAuth';\nimport { service } from './service';\n\nconst app = express();\n\n// Basic middlewares\napp.use(express.json());\napp.use(cookieParser());\n\n// Initiate SAML SP redirect\napp.get('/login', auth.initiate());\n\n// Handle SAML document POST back. User redirected to '/dashboard' on successful authentication\napp.post(\n  '/api/auth/callback',\n  authInstance.authenticate(),\n  (req, res, next) =\u003e {\n    res.redirect('/dashboard);\n  }\n);\n\n// Protect endpoints with local session authorization. Unauthorized users redirected to '/login' here\napp.get(\n  '/dashboard',\n  auth.authorize({ redirectUrl: '/login' }),\n  async (req, res) =\u003e {\n    // Utilize SAML user properties in authorized session endpoints\n    const dashboardStuff = await service.getDashboardStuff(req.user.encodedSUID);\n\n    res.json({ data: dashboardStuff });\n  }\n);\n\n// Log users out of local session and redirect them to '/home'\napp.get('/logout', auth.destroySession('/home'));\n\n// A public homepage for completeness\napp.get('/home', (req, res) =\u003e {\n  const homeStuff = await service.getHomeStuff();\n\n  res.json({ data: homeStuff });\n})\n\napp.listen(3000);\n```\n\n### Required middlewares\nIt should be noted that these middleware expect certain other basic middlewares to be present.\nMost notably, you should have [`express.json`](https://expressjs.com/en/api.html#express.json)\nand [`cookie-parser`](http://expressjs.com/en/resources/middleware/cookie-parser.html) middlewares\nsetup as there is an expectation that we will be able to access data at `req.body` and `req.cookies`.\n\n### Usage in Lambda functions\n\nTo use AdaptAuth middlewares in a lambda function all you need to do is create a simple\nexpress application for your handler that uses the middleware, then wrap it with\n[serverless-http](https://github.com/dougmoscrop/serverless-http).\nHere's a link to a [Netlify post](https://www.netlify.com/blog/2018/09/13/how-to-run-express.js-apps-with-netlify-functions/)\nthat goes through the whole process :wink:.\n\n### Usage with Next.js API routes\nIf you're using [Next.js api routes](https://nextjs.org/docs/api-routes/introduction) you can easily\nintegrate the AdaptAuth middlewares with the [next-connect](https://github.com/hoangvvo/next-connect) package.\nIt provides a simple connect interface that outputs a `NextApiHandler`! Boom! :collision: done.\n\n## API\n### `AdaptAuth.initiate()`\n\nCreates a middleware handler that simply redirects the request to the adapt-sso-sp servicer provider\nwith the confgiured paramters for entity and returnTo url. Note that this also handles passing along\na `final_destination` if present in `req.query.final_destination` to be added to the SAML RelayState.\n\n```typescript\napp.get('/saml/login', auth.initiate());\n```\n\n### `AdaptAuth.initialize()`\nThis is a simple pass-through of passports initialze middleware. It must be called prior to `AdaptAuth.authenticateSaml`\n\n### `AdaptAuth.authenticateSaml`\nSimple pass-through of `passport.authenticate` with confgired SamlStrategy. Required `AdaptAuth.initialize` middleware to have run prior.\n\n### `AdaptAuth.signToken(user: AuthUser)`\nSimple utility function to sign session jwts with the configured secrets and passed user as payload.\n\n### `AdaptAuth.verifyToken(token: string)`\nSimple utility to verify and decode session jwts. Rejects on invalid token. Resolves decoded user payload.\n\n### `AdaptAuth.createSession()`\nSimple middleware for saving the authenticated SAML user to a local jwt session. Creates an http only secure cookie\nwith SAML user payload as well as a basic http cookie signifying that the session exists.\n**NOTE:** This middleware expects to find a valid SamlUser on the request object at `req.user`. It will return a `401` otherwise.\n\n### `AdaptAuth.destroySession(redirectUrl?: string)`\nMiddleware that destroys local jwt session and redirects.\n\n- `redirectUrl?: string` Local path to redirect to after session destroyed. Overrides `config.logoutRedirectUrl`.\n\n```typescript\napp.get('/logout', auth.destroySession('/public-homepage'));\n```\n\n### `AdaptAuth.authenticate()`\nThis middleware is a wrapper for the entire authentication process intended to be used as the saml POST back endpoint.\nIt handles passport initialization, SAML document verification, and local jwt session creation.\n\n```typescript\napp.post('/handle/saml', auth.authenticate());\n```\n\n### `AdaptAuth.authorize(options?: AuthorizeOptions = {})`\nMiddleware to validate incoming requests against the local jwt session.\n\n#### `AuthorizeOptions`\n- `options.allowUnauthorized?: boolean` - Allow unauthorized requests to go to next middleware (useful for auth optional endpoints)\n- `options.redirectUrl?: string` - URL to redirect to on unauthorized. Will override `config.unauthorizedRedirectUrl` if set.\n\n```typescript\napp.get(\n  '/user-details',\n  auth.authorize({ redirectUrl: '/login' }),\n  async (req, res) =\u003e {\n    const user = await getUser();\n    res.json(user);\n  }\n)\n```\n\n### `AdaptAuth.getFinalDestination(req: any)`\nHelper function to extract possible `finalDestination` url from SAML relay state on request object.\n\n- `req: any` The request object to extract saml final destination from\n\n\n### Caveats when using on Netlify-hosted sites\nIf you are using https://github.com/bencao/netlify-plugin-inline-functions-env to inline your environment variables, \nbe aware that it only replaces process.env.[variable_name] usages for files inside your functions directory. \n\nBecause of this, you should not rely on the singleton object or the defaults provided by the constructor.\nYou'll need to initate an AdaptAuth instance inside a file in your functions directory, and pass in the full list of options. \nIt's fine to copy-paste these from the constructor in src/AdaptAuth.ts as a starting point, as shown below:\n\n```\nconst authInstance = new AdaptAuth({\n  saml: {\n    serviceProviderLoginUrl: process.env.ADAPT_AUTH_SAML_SP_URL || 'https://adapt-sso-uat.stanford.edu/api/sso/login',\n    entity: process.env.ADAPT_AUTH_SAML_ENTITY || 'adapt-sso-uat',\n    cert: process.env.ADAPT_AUTH_SAML_CERT,\n    decryptionKey: process.env.ADAPT_AUTH_SAML_DECRYPTION_KEY,\n    returnTo: process.env.ADAPT_AUTH_SAML_RETURN_URL,\n    returnToOrigin: siteUrl,\n    returnToPath: process.env.ADAPT_AUTH_SAML_RETURN_PATH,\n  },\n  session: {\n    secret: process.env.ADAPT_AUTH_SESSION_SECRET,\n    name: process.env.ADAPT_AUTH_SESSION_NAME || 'adapt-auth',\n    expiresIn: process.env.ADAPT_AUTH_SESSION_EXPIRES_IN || '12h',\n    loginRedirectUrl: process.env.ADAPT_AUTH_SESSION_LOGIN_URL || '/',\n    unauthorizedRedirectUrl: process.env.ADAPT_AUTH_SESSION_UNAUTHORIZED_URL,\n  },\n});\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsu-sws%2Fadapt-auth-sdk","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsu-sws%2Fadapt-auth-sdk","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsu-sws%2Fadapt-auth-sdk/lists"}