Snippet for authentication flow (Oauth2)
Each time the SDK refreshes the accessToken
the freshTokensCallback
is called with the response. You can store this data in localStorage
or any other persistant data store. When you restart your application, you can check the data store for a refreshToken
and use that to authenticate with the SDK.
Copy import { createOAuth2Client } from "@extrahorizon/javascript-sdk" ;
const exh = createOAuth2Client ({
host : "" ,
clientId : "" ,
freshTokensCallback : (tokenData) => {
localStorage .setItem ( "refreshToken" , tokenData .refreshToken);
} ,
});
try {
const refreshToken = await localStorage .getItem ( "refreshToken" );
if (refreshToken) {
await exh . auth .authenticate ({
refreshToken ,
});
} else {
// redirect to /login
}
} catch (error) {
localStorage .removeItem ( "refreshToken" );
// redirect to /login
}
Snippet for authentication flow (Oauth1)
You need to capture the response from the authenticate
function when logging in with email
/ password
so that subsequent SDK initializations such as app restarts can use the key
/ secret
combination stored in persistent data storage to authenticate the current user.
Copy import { createOAuth1Client } from "@extrahorizon/javascript-sdk" ;
const exh = createOAuth1Client ({
host : "https://api.dev.exh-sandbox.extrahorizon.io" ,
consumerKey : "" ,
consumerSecret : "" ,
});
try {
const tokenData = await localStorage .getItem ( "tokenData" );
if (tokenData) {
await exh . auth .authenticate ({
token : tokenData .key ,
tokenSecret : tokenData .secret ,
});
} else {
// redirect to /login
const result = await exh . auth .authenticate ({
email : "" ,
password : "" ,
});
localStorage .setItem ( "tokenData" , result);
}
} catch (error) {
localStorage .removeItem ( "tokenData" );
// redirect to /login
}
Proxy client
The package export a client you can use in combination with a proxy service. The client will throw a typed error in case you need to redirect to the login page.
Copy import { createProxyClient } from "@extrahorizon/javascript-sdk" ;
const loginPageUrl = "https://yourDomain.com/login" ;
( async () => {
try {
const exh = createProxyClient ({ host : "api.dev.exh-sandbox.extrahorizon.io" });
await exh . users .me ();
} catch (error) {
if (
error instanceof UserNotAuthenticatedError ||
error instanceof OauthTokenError
) {
redirectToUrl ( ` ${ loginPageUrl } /?redirect= ${ window . location .url } ` );
}
}
})();
Local setup
If you want to use the proxy sdk locally, you need to make some changes to your local setup.
Add 127.0.0.1 local.yourdomain.com
to your /etc/hosts
file (or if you are using Windows c:\Windows\System32\Drivers\etc\hosts
)
Start your server with https enabled.
For Mac/Linux, this can be done by running HTTPS=true yarn start
.
For Windows, you have to add HTTPS=true
to your user environment. Once the variable has been set, run yarn start
.
Open your browser https://local.yourdomain.com:3000/
and skip the security warning.
Snippet for stored credentials
When you already use the exh/cli
tool, you can use this snippet to initialize. More info: https://docs.extrahorizon.com/cli/setup/credentials
Copy import fs from "fs" ;
import path from "path" ;
import {
parseStoredCredentials ,
createOAuth1Client ,
} from "@extrahorizon/javascript-sdk" ;
const EXH_CONFIG_FILE = path .join ( process . env . HOME , "/.exh/credentials" );
const readFile = () => {
try {
return fs .readFileSync ( EXH_CONFIG_FILE , "utf-8" );
} catch (err) {
throw new Error (
`Failed to open credentials file. Make sure they are correctly specified in ${ EXH_CONFIG_FILE } `
);
}
};
try {
const credentials = parseStoredCredentials ( readFile ());
const exh = createOAuth1Client ({
consumerKey : credentials . API_OAUTH_CONSUMER_KEY ,
consumerSecret : credentials . API_OAUTH_CONSUMER_SECRET ,
host : credentials . API_HOST ,
});
await exh . auth .authenticate ({
token : credentials . API_OAUTH_TOKEN ,
tokenSecret : credentials . API_OAUTH_TOKEN_SECRET ,
});
} catch (error) {
console .log (error);
}
Other examples
OAuth1
Token authentication with optional skip
The skipTokenCheck
saves ~300ms by skipping validation on your token
and tokenSecret
.
Copy import { createOAuth1Client } from "@extrahorion/javascript-sdk" ;
const exh = createOAuth1Client ({
host : "sandbox.extrahorizon.io" ,
consumerKey : "" ,
consumerSecret : "" ,
});
await exh . auth .authenticate ({
token : "" ,
tokenSecret : "" ,
skipTokenCheck : true ,
});
Email authentication
Copy import { createOAuth1Client } from "@extrahorizon/javascript-sdk" ;
const exh = createOAuth1Client ({
host : "sandbox.extrahorizon.io" ,
consumerKey : "" ,
consumerSecret : "" ,
});
await exh . auth .authenticate ({
email : "" ,
password : "" ,
});
OAuth2
Password Grant flow
Copy import { createOAuth2Client } from "@extrahorizon/javascript-sdk" ;
const exh = createOAuth2Client ({
host : "" ,
clientId : "" ,
});
await exh . auth .authenticate ({
password : "" ,
username : "" ,
});
Authorization Code Grant flow with callback
Generating an Authorization Code is out of scope for this snippet, but generally:
Your application has a login/authorization page
It allows the user to login to your application
Shows the information about the (other, 3rd party) application requesting access
After consent to give access to the user its account, redirects the user to the application
The (3rd party) application then receives the Authorization Code in the query parameters
Capture the query params on the redirect uri
Authenticate with the code
query param
Copy import { createOAuth2Client } from "@extrahorizon/javascript-sdk" ;
const exh = createOAuth2Client ({
host : "" ,
clientId : "" ,
});
await exh . auth .authenticate ({
code : "" ,
});
Refresh Token Grant flow
Copy import { createOAuth2Client } from "@extrahorizon/javascript-sdk" ;
const exh = createOAuth2Client ({
host : "" ,
clientId : "" ,
});
await exh . auth .authenticate ({
refreshToken : "" ,
});
Password Grant flow with two-step MFA in try / catch
Copy import {
createOAuth2Client ,
MfaRequiredError ,
} from "@extrahorizon/javascript-sdk" ;
const exh = createOAuth2Client ({
host : "" ,
clientId : "" ,
});
try {
await exh . auth .authenticate ({
password : "" ,
username : "" ,
});
} catch (error) {
if (error instanceof MfaRequiredError ) {
const { mfa } = error;
// Your logic to request which method the user want to use in case of multiple methods
const methodId = mfa .methods[ 0 ].id;
await exh . auth .confirmMfa ({
token : mfa .token ,
methodId ,
code : "" , // code from ie. Google Authenticator
});
}
}
Confidential Applications
If you are using a confidential application in combination with React-Native. The SDK will add btoa
function to your global scope. See https://github.com/ExtraHorizon/javascript-sdk/issues/446
Copy const exh = createClient ({
host : "https://api.dev.exh-sandbox.extrahorizon.io" ,
clientId : "" ,
clientSecret : "" ,
});
Creating applications
Example
If you want to create an application can you use generic to determine the correct application and application version type.
ie. creating an OAuth1 application with a version.
Copy // Will return OAuth1Application type
const app = await exh . auth . applications .create ({
type : "oauth1" ,
name : "test" ,
description : "test" ,
});
// Will return OAuth1ApplicationVersion type
const version = await exh . auth . applications .createVersion < typeof app>( app .id , {
name : "1.0.0" ,
});
Typeguards
If you need a typeguard, you can use the following snippets.
Copy import {
Application ,
ApplicationVersion ,
OAuth1Application ,
OAuth1ApplicationVersion ,
} from "@extrahorizon/javascript-sdk" ;
function isOAuth1Version (
version : ApplicationVersion
) : version is OAuth1ApplicationVersion {
return `consumerKey` in version;
}
function isOAuth1 (app : Application ) : app is OAuth1Application {
return ! ( "redirectUris" in app);
}
const { data: apps } = await exh . auth . applications .get ();
apps .filter (isOAuth1) .forEach ((app) => {
// app will have type OAuth1Application
});
Last updated 8 months ago