Authorization Overview
These are instructions for connecting to the APIs using V2 Authentication. For V1 API Clients, please see Authorization Overview - V1
Introduction
Authentication allows your application to securely access merchant data via the APIs.
Merchants need to authorize your API client to access their data using the OAuth2 authorization code grant flow. No other authentication methods are supported.
The basic steps of the Authorization flow are:
-
Authorization Request: Provide the user with an authorization URL. The user clicks on the link, logs in, and consents to access. A
codeis returned to the redirect URI. -
Token Exchange: Capture the
codeand use it to send a request to the/tokenendpoint. Store theaccess_tokenandrefresh_tokenand their expiry times. -
Token Refresh: When the access token is close to expiring, send a request to the
/tokenendpoint with the latestrefresh_token. Store the newaccess_tokenand newrefresh_tokenand their expiry times.
Token expiry times should be monitored and managed dynamically
This article provides a general overview of the authorization flow. For a step-by-step walkthrough, see our Authentication Tutorial.
For information on obtaining an API Client, see Accessing the APIs.
The Authorization Flow
Obtaining an access token using the OAuth2 authorization code grant flow consists of the following steps:
1. Authorization Request
An authorization request is made when a Lightspeed Restaurant POS user clicks on a URL provided by the integrator.
The Authorization URL
Below are the URLs that should be used during the authorization process.
- The trial environment is used for development and testing of your application
- The production environment is used to connect your app to live merchant accounts.
API Clients are bound to the server they were issued for. This means that if you have a client for the trial environment, it will not work on the production environment. Likewise, if you have a production client, it will not work on the trial environment.
| Environment | Authorization URL |
|---|---|
| Trial | https://auth.lsk-demo.app/realms/k-series/protocol/openid-connect/auth |
| Production | https://auth.lsk-prod.app/realms/k-series/protocol/openid-connect/auth |
The following query parameters must be passed in the Authorization URL:
response_type(required) - Must becodefor the authorization code grant.client_id(required) - The unique identifier for the OAuth client.scope(required) - The access scopes being requested, space delimited (URL encoded).redirect_uri(required) - The URL that the user will be redirected to after authenticating and authorizing the integration. Must behttpsand match one of the redirect URIs registered for the API client.state(optional) - A unique string supplied by the external client that is persisted throughout the process to track the request.
Example Authorization URL
To connect to a merchant account on production, copy the following URL and replace the query parameter values with your own client ID, redirect URI, and scope(s). A state parameter can also be included, if desired.
https://auth.lsk-prod.app/realms/k-series/protocol/openid-connect/auth?response_type=code&client_id=DocumentationDemo-5745-4d30-8f1a-bd64511a62ed&redirect_uri=https://localhost&scope=financial-api%20orders-api&state=abcd123-efgh456
- This URL should be supplied to the Lightspeed merchant.
- When the user clicks on this URL, they will be prompted to login to their Lightspeed account.
- Upon successful login, the user must provide consent for the OAuth client to access their data:

2. Token Request
Once the user authorizes the application, a temporary authorization code is passed to your redirect URI as a query parameter. If the state parameter was supplied, it will also be included.
Example Redirect with Authorization Code:
https://your-redirect-uri/?session_state=26a01a6c-9603-4596-a48d-86bbcaa54ef8&iss=https%3A%2F%2Fauth.lsk-demo.app%2Frealms%2Fk-series&code=185a6985-b01a-4833-b289-fad154ea2039.26a01a6c-9603-4596-a48d-86bbcaa54ef8.0bb5b13a-f6a0-4da3-9915-f7633ded915f
The authorization code should be captured from the query parameter in the URL.
The code should then be exchanged for an access and refresh token pair by sending a POST request to the Token URL.
| Environment | Token URL |
|---|---|
| Trial | https://auth.lsk-demo.app/realms/k-series/protocol/openid-connect/token |
| Production | https://auth.lsk-prod.app/realms/k-series/protocol/openid-connect/token |
The client ID and client secret must be base64 encoded and passed as the authorization header in the following format client_id:client_secret.
For example:
DocumentationDemo-5745-4d30-8f1a-bd64511a62ed:fake-client-secret
becomes:
RG9jdW1lbnRhdGlvbkRlbW8tNTc0NS00ZDMwLThmMWEtYmQ2NDUxMWE2MmVkOmZha2UtY2xpZW50LXNlY3JldA==
The following values must be passed in the request body as a form-data payload.
grant_type=authorization_codecode: the code returned to redirect URI.redirect_uri: the redirect URI for the client.
Sample Request:
curl --location --request POST 'https://auth.lsk-demo.app/realms/k-series/protocol/openid-connect/token' \
--header 'Authorization: Basic RG9jdW1lbnRhdGlvbkRlbW8tNTc0NS00ZDMwLThmMWEtYmQ2NDUxMWE2MmVkOmZha2UtY2xpZW50LXNlY3JldA==' \
--form 'grant_type="authorization_code"' \
--form 'code="185a6985-b01a-4833-b289-fad154ea2039.26a01a6c-9603-4596-a48d-86bbcaa54ef8.0bb5b13a-f6a0-4da3-9915-f7633ded915f"' \ (replace with the code returned to redirect URI)
--form 'redirect_uri="https://localhost"' (replace with the redirect URI for the client)
Sample Response:
{
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJlZk51UFNodDNvUDVDNTM1X0tWYjVhX1B3aHJ6VmNSa25lbUY0ZFNTOTdNIn0.eyJleHAiOjE3NTMzOTEyMzAs...NvbSJ9.u85UrQxvE8tcJqOZIZRlXqtdtw6vTKevsbM3hj5Z_qhi7Z-2d-gr2DXNnNeobRikvaCRt3tPyQhjxBnlJA0mamW5hrAEV1-tEoRF6C59FuAOcVNnj3ZD7NN7_BHlBsAfRaUNU2q0nbnWxRTJItukRsiCOX6ogjBZjI3wF-6xdLdE4UVPMotuR4lcuPIyjJd6sVbg_OJvyGuHCibuDuGBMO7NhuRMQW9OSBT5FpAU_27p98RorB82EHG0tRWlCFvR_VKFvUbi6ESEqKrf97elnrve3pgvHNY8WkuQ8NF2rSsdMsu_-nCdG6w84K9m5RRY6ZFH2DMHQHlftA1Fzx9hGg",
"expires_in": 1500,
"refresh_expires_in": 1800,
"refresh_token": "eyJhbGciOiJIUzUxMiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJlMTM1NDA1OS0wYmFjLTQwYzUtOWVkZi1hODhmZjI1ZjVjZWEifQ.eyJleHAiOjE3NTMzOTE1MzAsImlhdCI6MT...Jhc2ljIHByb2ZpbGUifQ.gBHNDXCvDmksgTp5fsw5Mg1Wso91JgdG_0C6bIv6isc4HIRPGY8pfXW016QWBeutJG8Ea-PKucJqxj1I_GoOSw",
"token_type": "Bearer",
"not-before-policy": 0,
"session_state": "26a01a6c-9603-4596-a48d-86bbcaa54ef8",
"scope": "financial-api email profile"
}
3. Refreshing the Token
Refresh tokens can be exchanged for a new access and refresh token pair by sending a POST request to the /token endpoint.
The client ID and client secret must be base64 encoded and passed as the authorization header in the following format client_id:client_secret.
The values must be passed in the request body as an x-www-form-encoded payload. The endpoint will return a new access token and a new refresh token.
Sample Request:
curl \
--header 'Authorization: Basic c29tZV9jbGllbnRfaWQ6c29tZV9jbGllbnRfc2VjcmV0MQ==' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'grant_type=refresh_token' \
--data-urlencode 'refresh_token=138fc571-68b0-426d-82d3-b6386421788c' \
--request POST 'https://auth.lsk-demo.app/realms/k-series/protocol/openid-connect/token'
Sample Response:
{
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJlZk51UFNodDNvUDVDNTM1X0tWYjVhX1B3aHJ6VmNSa25lbUY0ZFNTOTdNIn0.eyJleHAiOjE3NTMzOTEyMzAs...NvbSJ9.u85UrQxvE8tcJqOZIZRlXqtdtw6vTKevsbM3hj5Z_qhi7Z-2d-gr2DXNnNeobRikvaCRt3tPyQhjxBnlJA0mamW5hrAEV1-tEoRF6C59FuAOcVNnj3ZD7NN7_BHlBsAfRaUNU2q0nbnWxRTJItukRsiCOX6ogjBZjI3wF-6xdLdE4UVPMotuR4lcuPIyjJd6sVbg_OJvyGuHCibuDuGBMO7NhuRMQW9OSBT5FpAU_27p98RorB82EHG0tRWlCFvR_VKFvUbi6ESEqKrf97elnrve3pgvHNY8WkuQ8NF2rSsdMsu_-nCdG6w84K9m5RRY6ZFH2DMHQHlftA1Fzx9hGg",
"expires_in": 1500,
"refresh_expires_in": 1800,
"refresh_token": "eyJhbGciOiJIUzUxMiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJlMTM1NDA1OS0wYmFjLTQwYzUtOWVkZi1hODhmZjI1ZjVjZWEifQ.eyJleHAiOjE3NTMzOTE1MzAsImlhdCI6MT...Jhc2ljIHByb2ZpbGUifQ.gBHNDXCvDmksgTp5fsw5Mg1Wso91JgdG_0C6bIv6isc4HIRPGY8pfXW016QWBeutJG8Ea-PKucJqxj1I_GoOSw",
"token_type": "Bearer",
"not-before-policy": 0,
"session_state": "26a01a6c-9603-4596-a48d-86bbcaa54ef8",
"scope": "financial-api email profile"
}
Quick Facts
Token Behavior
- If you do not use your refresh token within its expiry time, you will need to request a new access token.
- Access Token Expiry - 25 minutes
- Refresh Token Expiry
- With
offline_accessscope - 40 days - Without
offline_accessscope - 30 minutes
- With
- Session Duration
- With
offline_accessscope - No limit, as long as the refresh token is refreshed at least once every 30 days. - Without
offline_accessscope - 10 hours
- With
- For tokens with the
offline_accessscope, therefresh_token_validityfield will have a value of0.
Access Scopes
- The desired access scopes must be included in the
scopeparameter of the token request. They must be space delimited and URL encoded. - You will only be able to request the access scopes that your API client has been granted permission to request.
- Partners can make a request for additional scopes via the Developer Portal.
- Merchants can contact their account manager to request additional scopes.
- All clients are automatically granted
User ProfileandEmail addressscopes, in addition to the scopes specified. - The
offline_accessscope is a special scope that extends the lifetime of the refresh token and overall session duration. See Access Token Behavior for more details.
Redirect URIs
- Redirect URIs require
https. - Multiple Redirect URIs can be registered for a single API client, but only one can be included in the authorization URL at a time.
- Each refresh token can only be used once. Every time you refresh the access token, a new refresh token is also returned and the previous refresh token becomes invalid.