1"use strict";(self.webpackChunk_curri_docs=self.webpackChunk_curri_docs||[]).push([[1545],{7173:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>s,contentTitle:()=>a,default:()=>h,frontMatter:()=>c,metadata:()=>r,toc:()=>l});const r=JSON.parse('{"id":"getting-started/oauth-strategy","title":"How to authorize API access using OAuth 2.0","description":"This is a working document and is subject to change. If you are seeing this, we have already had direct communication with you and will not make any changes to functionality without confirming with you first.","source":"@site/docs/getting-started/oauth-strategy.md","sourceDirName":"getting-started","slug":"/getting-started/oauth-strategy","permalink":"/docs/getting-started/oauth-strategy","draft":false,"unlisted":true,"tags":[],"version":"current","frontMatter":{"title":"How to authorize API access using OAuth 2.0","unlisted":true}}');var o=t(678),i=t(9787);const c={title:"How to authorize API access using OAuth 2.0",unlisted:!0},a=void 0,s={},l=[{value:"Gather Project and Client Details from Curri",id:"gather-project-and-client-details-from-curri",level:3},{value:"Generate the Code Challenge and Verifier",id:"generate-the-code-challenge-and-verifier",level:3},{value:"Create the Authorization link",id:"create-the-authorization-link",level:3},{value:"Consent Form",id:"consent-form",level:3},{value:"Return to Requesting Application",id:"return-to-requesting-application",level:3},{value:"Accessing Curri's API",id:"accessing-curris-api",level:3},{value:"Refreshing the Bearer Token",id:"refreshing-the-bearer-token",level:3}];function d(e){const n={admonition:"admonition",code:"code",h3:"h3",li:"li",p:"p",pre:"pre",ul:"ul",...(0,i.R)(),...e.components};return(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)(n.admonition,{type:"note",children:(0,o.jsx)(n.p,{children:"This is a working document and is subject to change. If you are seeing this, we have already had direct communication with you and will not make any changes to functionality without confirming with you first."})}),"\n",(0,o.jsx)(n.h3,{id:"gather-project-and-client-details-from-curri",children:"Gather Project and Client Details from Curri"}),"\n",(0,o.jsxs)(n.p,{children:["In order to setup your integration to Curri's OAuth flow, you first need to obtain Client IDs for generating ",(0,o.jsx)(n.code,{children:"Sandbox"})," and ",(0,o.jsx)(n.code,{children:"Production"})," authorization tokens, as well as the requisite Project Name used to generate the proper authorization URI."]}),"\n",(0,o.jsx)(n.h3,{id:"generate-the-code-challenge-and-verifier",children:"Generate the Code Challenge and Verifier"}),"\n",(0,o.jsx)(n.p,{children:"The Requesting Application needs to generate a Code Challenge and Verifier for PKCE"}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-javascript",children:"const crypto = require('crypto')\n\nconst base64UrlEncode = value =>\n value\n .toString('base64')\n .replace(/\\+/g, '-')\n .replace(/\\//g, '_')\n .replace(/=/g, '')\n\nconst sha256 = buffer => crypto.createHash('sha256').update(buffer).digest()\n\nconst codeVerifier = base64UrlEncode(crypto.randomBytes(32))\nconst codeChallenge = base64UrlEncode(sha256(codeVerifier))\n\nconsole.log({ codeChallenge, codeVerifier })\n"})}),"\n",(0,o.jsx)(n.h3,{id:"create-the-authorization-link",children:"Create the Authorization link"}),"\n",(0,o.jsxs)(n.p,{children:["The Requesting Application will use the ",(0,o.jsx)(n.code,{children:"codeChallenge"})," generated above to create a URL for the user, where they can authenticate with Curri."]}),"\n",(0,o.jsxs)(n.ul,{children:["\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.code,{children:"state"})," is a string of random characters, used for CSRF protection"]}),"\n"]}),"\n",(0,o.jsx)(n.p,{children:"Below has sample code that will generate the link:"}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-javascript",children:"const clientId = 'your-client-id'\nconst projectName = 'project-name'\nconst authUrl = `https://${projectName}.projects.oryapis.com/oauth2/auth`\nconst redirectUri = 'https://help.curri.com'\nconst codeChallenge = '[codeChallenge]'\n\nconsole.log(\n `https://${authUrl}?response_type=code&client_id=${clientId}&redirect_uri=${redirectUri}&scope=offline_access&code_challenge=${codeChallenge}&code_challenge_method=S256&state=${base64UrlEncode(\n crypto.randomBytes(32)\n )}`\n)\n"})}),"\n",(0,o.jsx)(n.h3,{id:"consent-form",children:"Consent Form"}),"\n",(0,o.jsx)(n.p,{children:"After authentication, the user will be taken to the consent form where they can grant or deny access to Curri's resources from the Requesting Application. Afterwards, the user will be redirected back to the Requesting Application."}),"\n",(0,o.jsx)(n.h3,{id:"return-to-requesting-application",children:"Return to Requesting Application"}),"\n",(0,o.jsxs)(n.p,{children:["Upon returning, and having granted access, the URL will contain a ",(0,o.jsx)(n.code,{children:"code"})," parameter. The Requesting Application can exchange that ",(0,o.jsx)(n.code,{children:"code"})," for a Bearer Token."]}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-javascript",children:"const clientId = 'your-client-id'\nconst projectName = 'project-name'\nconst tokenUrl = `https://${projectName}.projects.oryapis.com/oauth2/token`\nconst codeVerifier = '[codeVerifier]' // Generated from the first step\nconst code = '[code]'\nconst redirectUri = 'https://help.curri.com'\nconst requestBody = `grant_type=authorization_code&client_id=${clientId}&code_verifier=${codeVerifier}&code=${code}&redirect_uri=${redirectUri}`\n\nfetch(tokenUrl, {\n body: requestBody,\n headers: { 'Content-Type': 'application/x-www-form-urlencoded' },\n method: 'POST',\n})\n .then(response => response.json())\n .then(data => console.log(data))\n .catch(error => console.error(error))\n\n// Response Body\n// {\n// access_token: '[token]',\n// expires_in: 3599,\n// refresh_token: '[refresh_token]',\n// scope: 'offline_access',\n// token_type: 'bearer'\n// }\n"})}),"\n",(0,o.jsx)(n.h3,{id:"accessing-curris-api",children:"Accessing Curri's API"}),"\n",(0,o.jsx)(n.p,{children:"The Requesting Application may now access Curri's API by providing the Bearer Token."}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-sh",children:'curl --silent --show-error --location --include \\\n --header "Authorization: Bearer [token]" \\\n --header "Content-Type: application/json" \\\n --data \'{"query": "query { currentUser { id firstName lastName } }"}\' \\\n --request POST "https://api.curri.com/graphql"\n'})}),"\n",(0,o.jsx)(n.h3,{id:"refreshing-the-bearer-token",children:"Refreshing the Bearer Token"}),"\n",(0,o.jsxs)(n.p,{children:["The Requesting Application may request a new Bearer Token by supplying the\n",(0,o.jsx)(n.code,{children:"[refreshToken]"})," that came with the previous Bearer Token."]}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-javascript",children:"const clientId = 'your-client-id'\nconst projectName = 'project-name'\nconst tokenUrl = `https://${projectName}.projects.oryapis.com/oauth2/token`\nconst refreshToken = '[refreshToken]'\nconst requestBody = `grant_type=refresh_token&client_id=${clientId}&&refresh_token=${refreshToken}`\n\nfetch(tokenUrl, {\n body: requestBody,\n headers: { 'Content-Type': 'application/x-www-form-urlencoded' },\n method: 'POST',\n})\n .then(response => {\n if (!response.ok) {\n throw new Error('Failed to refresh access token')\n }\n\n return response.json()\n })\n .then(data => console.log(data))\n .catch(error => console.error(error))\n"})})]})}function h(e={}){const{wrapper:n}={...(0,i.R)(),...e.components};return n?(0,o.jsx)(n,{...e,children:(0,o.jsx)(d,{...e})}):d(e)}},9787:(e,n,t)=>{t.d(n,{R:()=>c,x:()=>a});var r=t(6166);const o={},i=r.createContext(o);function c(e){const n=r.useContext(i);return r.useMemo(function(){return"function"==typeof e?e(n):{...n,...e}},[n,e])}function a(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(o):e.components||o:c(e.components),r.createElement(i.Provider,{value:n},e.children)}}}]);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.