|
| 1 | +import { Callout } from "nextra/components" |
| 2 | +import { Code } from "@/components/Code" |
| 3 | + |
| 4 | +<img align="right" src="/img/providers/sailpoint.svg" height="64" width="64" /> |
| 5 | + |
| 6 | +# SailPoint Identity Secure Cloud Provider |
| 7 | + |
| 8 | +SailPoint Identity Secure Cloud (ISC) is an enterprise SaaS platform for identity and security. In order to use this OAuth integration, you will need an ISC tenant. If you're a SailPoint customer or partner, please talk to your SailPoint account manager for more details. If you are a developer, you can check out the [SailPoint Developer Community](https://developer.sailpoint.com/discuss/). |
| 9 | + |
| 10 | +## Resources |
| 11 | + |
| 12 | +- [SailPoint Identity Secure Cloud Authentication](https://developer.sailpoint.com/docs/api/authentication#choose-authorization-grant-flow) |
| 13 | +- [Managing API Keys and Personal Access Tokens](https://documentation.sailpoint.com/saas/help/common/api_keys.html?h=oauth+client#creating-an-api-key) |
| 14 | +- [SailPoint Developer Community](https://developer.sailpoint.com/discuss/) |
| 15 | + |
| 16 | +## Setup |
| 17 | + |
| 18 | +### Callback URL |
| 19 | + |
| 20 | +<Code> |
| 21 | + <Code.Next> |
| 22 | + |
| 23 | +```bash |
| 24 | +https://example.com/api/auth/callback/identitySecureCloud |
| 25 | +``` |
| 26 | + |
| 27 | + </Code.Next> |
| 28 | + <Code.Svelte> |
| 29 | + |
| 30 | +```bash |
| 31 | +https://example.com/auth/callback/identitySecureCloud |
| 32 | +``` |
| 33 | + |
| 34 | + </Code.Svelte> |
| 35 | +</Code> |
| 36 | + |
| 37 | +### Create OAuth Client |
| 38 | + |
| 39 | +Find your Identity Secure Cloud Tenant OAuth Information which can be found at `https://{tenant}.api.identitynow.com/oauth/info`. Create an OAuth Client (following this [guide](https://documentation.sailpoint.com/saas/help/common/api_keys.html?h=oauth+client#creating-an-api-key)) with grant types: `AUTHORIZATION_TOKEN` and `REFRESH_TOKEN`. Redirect URL should match your version of the Callback URL above. Finally, select the scopes `sp:scope:all`. Note down the generated `clientId` and `clientSecret`. |
| 40 | + |
| 41 | +### Environment Variables |
| 42 | + |
| 43 | +``` |
| 44 | +ISC_BASE_API_URL=https://{tenant}.api.identitynow.com |
| 45 | +ISC_BASE_URL=https://{tenant}.identitynow.com |
| 46 | +ISC_CLIENT_ID= |
| 47 | +ISC_CLIENT_SECRET= |
| 48 | +``` |
| 49 | + |
| 50 | +### Configuration |
| 51 | + |
| 52 | +<Code> |
| 53 | + <Code.Next> |
| 54 | + |
| 55 | +```ts filename="/auth.ts" |
| 56 | +import NextAuth from "next-auth" |
| 57 | + |
| 58 | +export const { handlers, auth, signIn, signOut } = NextAuth({ |
| 59 | + providers: [ |
| 60 | + { |
| 61 | + id: "identitySecureCloud", |
| 62 | + name: "Identity Secure Cloud", |
| 63 | + type: "oauth", |
| 64 | + clientId: process.env.ISC_CLIENT_ID!, |
| 65 | + clientSecret: process.env.ISC_CLIENT_SECRET!, |
| 66 | + authorization: { |
| 67 | + url: `${process.env.ISC_BASE_URL!}/oauth/authorize`, |
| 68 | + params: { scope: 'sp:scopes:all' }, |
| 69 | + }, |
| 70 | + token: `${process.env.ISC_BASE_API_URL!}/oauth/token`, |
| 71 | + userinfo: `${process.env.ISC_BASE_API_URL!}/oauth/userinfo`, |
| 72 | + profile(profile) { |
| 73 | + return { |
| 74 | + id: profile.id, |
| 75 | + email: profile.email, |
| 76 | + name: profile.uid, |
| 77 | + image: null |
| 78 | + } |
| 79 | + }, |
| 80 | + style: { text: "#011E69", bg: "#fff", logo: "sailpoint.svg" }, |
| 81 | + }, |
| 82 | + ], |
| 83 | +}) |
| 84 | +``` |
| 85 | + |
| 86 | + </Code.Next> |
| 87 | + <Code.Svelte> |
| 88 | + |
| 89 | +```ts filename="/src/auth.ts" |
| 90 | +import { SvelteKitAuth } from "@auth/sveltekit" |
| 91 | +import { env } from "$env/dynamic/prviate" |
| 92 | + |
| 93 | +export const { handle, signIn, signOut } = SvelteKitAuth({ |
| 94 | + providers: [ |
| 95 | + { |
| 96 | + id: "identitySecureCloud", |
| 97 | + name: "Identity Secure Cloud", |
| 98 | + type: "oauth", |
| 99 | + clientId: env.ISC_CLIENT_ID!, |
| 100 | + clientSecret: env.ISC_CLIENT_SECRET!, |
| 101 | + authorization: { |
| 102 | + url: `${env.ISC_BASE_URL!}/oauth/authorize`, |
| 103 | + params: { scope: 'sp:scopes:all' }, |
| 104 | + }, |
| 105 | + token: `${env.ISC_BASE_API_URL!}/oauth/token`, |
| 106 | + userinfo: `${env.ISC_BASE_API_URL!}/oauth/userinfo`, |
| 107 | + profile(profile) { |
| 108 | + return { |
| 109 | + id: profile.id, |
| 110 | + email: profile.email, |
| 111 | + name: profile.uid, |
| 112 | + image: null |
| 113 | + } |
| 114 | + }, |
| 115 | + style: { text: "#011E69", bg: "#fff", logo: "sailpoint.svg" }, |
| 116 | + }, |
| 117 | + ], |
| 118 | +}) |
| 119 | +``` |
| 120 | + |
| 121 | + </Code.Svelte> |
| 122 | + <Code.Express> |
| 123 | + |
| 124 | +```ts filename="/src/app.ts" |
| 125 | +import { ExpressAuth } from "@auth/express" |
| 126 | + |
| 127 | +app.use("/auth/*", ExpressAuth({ providers: [ |
| 128 | + { |
| 129 | + id: "identitySecureCloud", |
| 130 | + name: "Identity Secure Cloud", |
| 131 | + type: "oauth", |
| 132 | + clientId: process.env.ISC_CLIENT_ID!, |
| 133 | + clientSecret: process.env.ISC_CLIENT_SECRET!, |
| 134 | + authorization: { |
| 135 | + url: `${process.env.ISC_BASE_URL!}/oauth/authorize`, |
| 136 | + params: { scope: 'sp:scopes:all' }, |
| 137 | + }, |
| 138 | + token: `${process.env.ISC_BASE_API_URL!}/oauth/token`, |
| 139 | + userinfo: `${process.env.ISC_BASE_API_URL!}/oauth/userinfo`, |
| 140 | + profile(profile) { |
| 141 | + return { |
| 142 | + id: profile.id, |
| 143 | + email: profile.email, |
| 144 | + name: profile.uid, |
| 145 | + image: null |
| 146 | + } |
| 147 | + }, |
| 148 | + style: { text: "#011E69", bg: "#fff", logo: "sailpoint.svg" }, |
| 149 | + }, |
| 150 | +] })) |
| 151 | +``` |
| 152 | + |
| 153 | + </Code.Express> |
| 154 | +</Code> |
| 155 | + |
| 156 | +Your `userprofile` endpoint will return more fields, but by default the [User table](https://authjs.dev/getting-started/database#models) only supports `id`, `name`, `email`, and `image`. Therefore, if you'd like to use any of the following fields, make sure you modify the `User` table schema in whichever adapter / database you're using. |
| 157 | + |
| 158 | +```ts |
| 159 | +tenant: profile.tenant, |
| 160 | +id: profile.id, |
| 161 | +uid: profile.uid, |
| 162 | +email: profile.email, |
| 163 | +phone: profile.phone, |
| 164 | +workPhone: profile.workPhone, |
| 165 | +firstname: profile.firstname, |
| 166 | +lastname: profile.lastname, |
| 167 | +capabilities: profile.capabilities, |
| 168 | +displayName: profile.displayName, |
| 169 | +name: profile.uid |
| 170 | +``` |
| 171 | + |
| 172 | +The above fields will all be available in the `profile` callback. |
0 commit comments