Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
148 changes: 148 additions & 0 deletions documents/oAuthTokenClient.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
## OAuth Token Client

### Generate Authorize Url
```js

const OAuthTokenClient = require("./dist/oAuthTokenClient");
const { generateOnboardingSignature } = require("./dist/utils/razorpay-utils")

// Initialize client
let oAuth = new OAuthTokenClient();

let attributes = {
"submerchant_id": "<SUBMERCHANT_MID>",
"timestamp": Math.floor(Date.now() / 1000)
}

let onboarding_signature = generateOnboardingSignature(attributes, "<YOUR_CLIENT_SECRET>");

// Not an promise
const authUrl = oAuth.generateAuthUrl({
"client_id": "<YOUR_CLIENT_ID>",
"response_type": "code",
"redirect_uri": "https://example.com/razorpay_callback",
"scope": ["read_write"],
"state": "NOBYtv8r6c75ex6WZ",
"onboarding_signature": onboarding_signature
});

console.log(authUrl)
```

**Parameters:**

| Name | Type | Description |
|----------------------|--|---------------------------------------------------------------------------------------------------------------------------------------------------------|
| client_id* | string | Unique client identifier. |
| redirect_uri* | string | Callback URL used by Razorpay to redirect after the user approves or denies the authorisation request. The client should whitelist the 'redirect_uri'. |
| scopes* | array | Defines what access your application is requesting from the user. You can request one or multiple scopes by adding them to an array as indicated above. |
| state* | string | A random string generated by your service. This parameter helps prevent cross-site request forgery (CSRF) attacks. |
| onboarding_signature | string | A cryptographic string generated by your service using generateOnboardingSignature method in Utils class. Only applicable for accounts created with pre-fill KYC |

**Response:**
```
"https://auth.razorpay.com/authorize?response_type=code&client_id=<YOUR_CLIENT_ID>&redirect_uri=https:%2F%2Fexample.com%2Frazorpay_callback&scope[]=read_only&scope[]=rx_read_write&state=NOBYtv8r6c75ex6WZ&onboarding_signature=<GENERATED_ONBOARDING_SIGNATURE>"
```

-------------------------------------------------------------------------------------------------------

### Get Access token
```js
oAuth.getAccessToken({
"client_id": "<YOUR_CLIENT_ID>",
"client_secret": "<YOUR_CLIENT_SECRET>",
"grant_type": "authorization_code",
"redirect_uri": "https://example.com",
"code": "def50200d844dc80cc44dce2c665d07a374d76802",
"mode": "test"
})
```

**Parameters:**

| Name | Type | Description |
|----------------|--------|------------------------------------------------------------------------------------------------------------------------------|
| client_id* | string | Unique client identifier. |
| client_secret* | string | Client secret string. |
| redirect_uri* | string | Specifies the same redirect_uri used in the authorisation request. |
| grant_type* | string | Defines the grant type for the request. Possible value are:<ul><li>authorization_code</li><li>client_credentials</li></ul> |
| code* | string | Decoded authorisation code received in the last step. Note: Pass this parameter only when grant_type is 'authorization_code' |
| mode | string | The type of mode. Possible values: <ul><li>test</li><li>live (default)</li></ul> |

**Response:**
```json
{
"public_token": "rzp_test_oauth_9xu1rkZqoXlClS",
"token_type": "Bearer",
"expires_in": 7862400,
"access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImp0aSI6IkY1Z0NQYkhhRzRjcUpnIn0.eyJhdWQiOiJGNFNNeEgxanMxbkpPZiIsImp0aSI6IkY1Z0NQYkhhRzRjcUpnIiwiaWF0IjoxNTkyODMxMDExLCJuYmYiOjE1OTI4MzEwMTEsInN1YiI6IiIsImV4cCI6MTYwMDc3OTgxMSwidXNlcl9pZCI6IkYycVBpejJEdzRPRVFwIiwibWVyY2hhbnRfaWQiOiJGMnFQaVZ3N0lNV01GSyIsInNjb3BlcyI6WyJyZWFkX29ubHkiXX0.Wwqt5czhoWpVzP5_aoiymKXoGj-ydo-4A_X2jf_7rrSvk4pXdqzbA5BMrHxPdPbeFQWV6vsnsgbf99Q3g-W4kalHyH67LfAzc3qnJ-mkYDkFY93tkeG-MCco6GJW-Jm8xhaV9EPUak7z9J9jcdluu9rNXYMtd5qxD8auyRYhEgs",
"refresh_token": "def50200f42e07aded65a323f6c53181d802cc797b62cc5e78dd8038d6dff253e5877da9ad32f463a4da0ad895e3de298cbce40e162202170e763754122a6cb97910a1f58e2378ee3492dc295e1525009cccc45635308cce8575bdf373606c453ebb5eb2bec062ca197ac23810cf9d6cf31fbb9fcf5b7d4de9bf524c89a4aa90599b0151c9e4e2fa08acb6d2fe17f30a6cfecdfd671f090787e821f844e5d36f5eacb7dfb33d91e83b18216ad0ebeba2bef7721e10d436c3984daafd8654ed881c581d6be0bdc9ebfaee0dc5f9374d7184d60aae5aa85385690220690e21bc93209fb8a8cc25a6abf1108d8277f7c3d38217b47744d7",
"razorpay_account_id": "acc_Dhk2qDbmu6FwZH"
}
```
-------------------------------------------------------------------------------------------------------

### Get Access token using refresh token
```js
oAuth.refreshToken({
"client_id": "<YOUR_CLIENT_ID>",
"client_secret": "<YOUR_CLIENT_SECRET>",
"grant_type": "authorization_code",
"refresh_token": "def50200d844dc80cc44dce2c665d07a374d76802"
})
```

**Parameters:**

| Name | Type | Description |
|----------------|-----------|--------------------------------------------|
| client_id* | string | Unique client identifier. |
| client_secret* | string | Client secret string. |
| grant_type* | string | Defines the grant type for the request. Possible value are:<ul><li>authorization_code</li><li>client_credentials</li></ul> |
| refresh_token* | string | The previously-stored refresh token value. |


**Response:**
```json
{
"public_token": "rzp_test_oauth_9xu1rkZqoXlClS",
"token_type": "Bearer",
"expires_in": 7862400,
"access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImp0aSI6Ijl4dTF",
"refresh_token": "def5020096e1c470c901d34cd60fa53abdaf36620e823ffa53"
}
```

-------------------------------------------------------------------------------------------------------

### Revoke a token
```js
oAuth.revokeToken({
"client_id": "<YOUR_CLIENT_ID>",
"client_secret": "<YOUR_CLIENT_SECRET>",
"token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImp0aSI6Ijl4dTF",
"token_type_hint": "access_token"
})
```

**Parameters:**

| Name | Type | Description |
|------------------|----------|----------------------------------------------------------------------------------------------------------|
| client_id* | string | Unique client identifier. |
| client_secret* | string | Client secret string. |
| token_type_hint* | string | The type of token for the request. Possible values: <ul><li>access_token</li><li>refresh_token</li></ul> |
| token* | string | The token whose access should be revoked. |

**Response:**
```json
{
"message": "Token Revoked"
}
```
-------------------------------------------------------------------------------------------------------

**PN: * indicates mandatory fields**
<br>
<br>
**For reference click [here](https://razorpay.com/docs/partners/platform/onboard-businesses/integrate-oauth/integration-steps)**
31 changes: 23 additions & 8 deletions lib/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,17 +40,32 @@ function normalizeError(err) {

class API {
constructor(options) {
this.rq = axios.create({
this.rq = axios.create(this._createConfig(options))
}

_createConfig(options) {
const config = {
baseURL: options.hostUrl,
auth: {
username: options.key_id,
password: options.key_secret
},
headers: Object.assign(
{'User-Agent': options.ua},
{ 'User-Agent': options.ua },
getValidHeaders(options.headers)
)
})
),
};

if (options.key_id && options.key_secret) {
config.auth = {
username: options.key_id,
password: options.key_secret,
};
}

if(options.oauthToken){
config.headers = {
'Authorization': `Bearer ${options.oauthToken}`,
...config.headers
}
}
return config;
}

version = 'v1';
Expand Down
132 changes: 132 additions & 0 deletions lib/oAuthTokenClient.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
import API, { INormalizeError } from "./types/api"

declare namespace OAuthTokenClient {

interface OAuthTokenBaseRequestBody {
/**
* Unique client identifier.
*/
client_id: string;
/**
* Client secret string.
*/
client_secret: string;
}

interface InitiateAuthorisationRequest extends Pick<OAuthTokenBaseRequestBody, 'client_id'>{
/**
* Specifies that the application is requesting an
* authorisation code grant. possible value is `code`.
*/
response_type: string;
/**
* Callback URL used by Razorpay to redirect after the user approves or denies the authorisation request.
* The client should whitelist the `redirect_uri`.
*/
redirect_uri: string;
/**
* Defines what access your application is requesting from the user. You can request multiple scopes
* by separating with a space.
* possible values is `read_only` or `read_write`.
*/
scope: string | string[];
/**
* Check [doc](https://razorpay.com/docs/partners/technology-partners/onboard-businesses/integrate-oauth/integration-steps/#query-parameters) for required params
*/
state: string;
onboarding_signature?: string;
}

interface OAuthTokenRequest extends OAuthTokenBaseRequestBody {
/**
* Defines the grant type for the request. possible value is `authorization_code` or `refresh_token`
*/
grant_type?: "authorization_code" | "refresh_token";
/**
* Specifies the same `redirect_uri` used in the authorisation request.
*/
redirect_uri?: string;
/**
* Decoded authorisation code received in the last step.
*/
code?: string;
/**
* The type of mode. possible values is `test` or `live`.
*/
mode?: "test" | "live";
/**
* Used to refresh the access token when it expires.
*/
refresh_token?: string;
/**
* The type of token for the request. possible value is `access_token` or `refresh_token`.
*/
token_type_hint?: "access_token" | "refresh_token";
/**
* The token whose access should be revoked.
*/
token?: string;
}

interface OAuthTokenTokenResponse {
/**
* A public key is used only for public routes such as Checkout or Payments.
*/
public_token: string;
/**
* Defines the type of access token. possible value is `Bearer`
*/
token_type: string;
/**
* Integer representing the TTL of the access token in seconds.
*/
expires_in: number;
/**
* A private key used to access sub-merchant resources on Razorpay.
* used for server-to-server calls only.
*/
access_token: string;
/**
* Used to refresh the access token when it expires.
*/
refresh_token:string;
/**
* Identifies the sub-merchant ID who granted the authorisation.
*/
razorpay_account_id: string;
}
}

declare class OAuthTokenClient extends API{
constructor()

getEntityUrl(): string;
/**
* Initiate Authorisation Using URL
* @param param - Check [doc](https://razorpay.com/docs/partners/technology-partners/onboard-businesses/integrate-oauth/integration-steps/#query-parameters) for required params
*/
generateAuthUrl(param: OAuthTokenClient.InitiateAuthorisationRequest): string;

/**
* Get access token
* @param param - Check [doc](https://razorpay.com/docs/partners/technology-partners/onboard-businesses/integrate-oauth/integration-steps/#request-parameters) for required params
*/
getAccessToken(param: OAuthTokenClient.OAuthTokenRequest): Promise<OAuthTokenClient.OAuthTokenTokenResponse>;
getAccessToken(param: OAuthTokenClient.OAuthTokenRequest, callback: (err: INormalizeError | null, data: OAuthTokenClient.OAuthTokenTokenResponse) => void): void

/**
* Get refresh token
* @param param - Check [doc](https://razorpay.com/docs/partners/technology-partners/onboard-businesses/integrate-oauth/integration-steps/#refresh-token-api) for required params
*/
refreshToken(param: OAuthTokenClient.OAuthTokenRequest): Promise<OAuthTokenClient.OAuthTokenTokenResponse>;
refreshToken(param: OAuthTokenClient.OAuthTokenRequest, callback: (err: INormalizeError | null, data: OAuthTokenClient.OAuthTokenTokenResponse) => void): void

/**
* Revoke token
* @param param - Check [doc](https://razorpay.com/docs/partners/technology-partners/onboard-businesses/integrate-oauth/integration-steps/#revoke-token-api) for required params
*/
revokeToken(param: OAuthTokenClient.OAuthTokenRequest): Promise<{ message: string;}>;
revokeToken(param: OAuthTokenClient.OAuthTokenRequest, callback: (err: INormalizeError | null, data: { message: string;}) => void): void
}

export = OAuthTokenClient
62 changes: 62 additions & 0 deletions lib/oAuthTokenClient.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
const API = require('./api');
const pkg = require('../package.json');
const { validateInput, SCHEMAS } = require('./resources/oAuthTokenValidator');

class OAuthTokenClient extends API{

constructor() {
super({
hostUrl : 'https://auth.razorpay.com',
ua: `razorpay-node@${pkg.version}`,
})
}

getEntityUrl(params){
return params.url ;
}

generateAuthUrl(params) {
const errors = validateInput(params, SCHEMAS.generateAuthUrl);
if (Object.keys(errors).length > 0) return errors;
const baseUrl = `${this.rq.defaults.baseURL}/authorize`;
const queryString = Object.entries(params)
.flatMap(([key, value]) =>

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why use flatMap instead of map ? can you explain that in a comment

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

to handle values like ['read_only', 'read_write'] and map to scope[]=read_only&scope[]=read_write

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please take @shwatang's approval on this

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Discussed over call.

to handle values like ['read_only', 'read_write'] and map to scope[]=read_only&scope[]=read_write

This logic is expected. Though how will this be implemented in JS is something you folks can take a call on.

Array.isArray(value)
? value.map(item => `${key}[]=${encodeURIComponent(item)}`)
: key === "redirect_uri"
? `${key}=${value}`
: `${key}=${encodeURIComponent(value)}`
)
.join("&");
return `${baseUrl}?${queryString}`;
}

getAccessToken(params = {}, callback){
const errors = validateInput(params, SCHEMAS.getAccessToken);
if (Object.keys(errors).length > 0) return Promise.reject(errors);
return this.post({
url: '/token',
data: params
}, callback)
}

refreshToken(params = {}, callback){
const errors = validateInput(params, SCHEMAS.refreshToken);
if (Object.keys(errors).length > 0) return Promise.reject(errors);
return this.post({
url: '/token',
data: params
}, callback)
}

revokeToken(params = {}, callback){
const errors = validateInput(params, SCHEMAS.revokeToken);
if (Object.keys(errors).length > 0) return Promise.reject(errors);
return this.post({
url: '/revoke',
data: params
}, callback)
}
}

module.exports = OAuthTokenClient
3 changes: 2 additions & 1 deletion lib/razorpay.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,10 @@ import documents from './types/documents'
import disputes from './types/disputes'

interface IRazorpayConfig {
key_id: string;
key_id?: string;
key_secret?: string;
headers?: RazorpayHeaders;
oauthToken?: string;
}

declare class Razorpay {
Expand Down
Loading