Customer Authentication
Use Tiquo as an OAuth 2.0 Authorization Server and OpenID Connect Provider
Customer Authentication with OAuth 2.0 / OIDC
Tiquo acts as a full OAuth 2.0 Authorization Server and OpenID Connect (OIDC) Provider. This lets you integrate customer authentication using the standard authorization code flow, which works with native mobile apps, server-side applications, and any platform that supports OAuth.
After a customer completes the OAuth flow, Tiquo issues JWT access tokens that work with the Customer API, just like tokens from the DOM Package.
Endpoints
| Endpoint | URL | Description |
|---|---|---|
| Discovery | https://edge.tiquo.app/api/auth/.well-known/openid-configuration | OIDC discovery metadata |
| OAuth Metadata | https://edge.tiquo.app/api/auth/.well-known/oauth-authorization-server | OAuth 2.0 server metadata |
| Authorization | https://edge.tiquo.app/api/auth/oauth2/authorize | Start the authorization flow |
| Token | https://edge.tiquo.app/api/auth/oauth2/token | Exchange code for tokens |
| UserInfo | https://edge.tiquo.app/api/auth/oauth2/userinfo | Get user claims |
| JWKS | https://edge.tiquo.app/api/auth/jwks | Public keys for token verification |
Setup
1. Register an OAuth Client
OAuth clients are registered through the Tiquo dashboard. Dynamic client registration is not available.
- Go to Settings > Identity Provider (IDP).
- In OAuth Clients, click Create OAuth Client.
- Enter a name and the exact redirect URI or URIs used by your application.
- Copy the
client_idandclient_secret. Store the secret securely; confidential clients need it during token exchange.
2. Authorization Flow
Redirect the customer to the authorization endpoint:
https://edge.tiquo.app/api/auth/oauth2/authorize?
client_id=your_client_id
&response_type=code
&redirect_uri=https://yourapp.com/callback
&scope=openid profile email offline_access
&state=random_state_value
&code_challenge=your_code_challenge
&code_challenge_method=S256| Parameter | Required | Description |
|---|---|---|
client_id | Yes | Your OAuth client ID |
response_type | Yes | Must be code |
redirect_uri | Yes | Where to redirect after authentication |
scope | No | Space-separated scopes. Include offline_access when the application needs a refresh token. |
state | Recommended | Random value for CSRF protection |
code_challenge | Recommended | PKCE code challenge (S256 method) |
code_challenge_method | Recommended | Must be S256 when using PKCE |
The customer will see a sign-in page where they authenticate with their email (via OTP). After authentication, Tiquo redirects back to your redirect_uri with an authorization code:
https://yourapp.com/callback?code=auth_code_here&state=random_state_value3. Exchange Code for Tokens
Exchange the authorization code for tokens:
curl -X POST "https://edge.tiquo.app/api/auth/oauth2/token" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=authorization_code" \
-d "code=auth_code_here" \
-d "redirect_uri=https://yourapp.com/callback" \
-d "client_id=your_client_id" \
-d "client_secret=your_client_secret" \
-d "code_verifier=your_code_verifier"Response:
{
"access_token": "eyJhbGciOiJSUzI1NiJ9...",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "rt_xxx...",
"id_token": "eyJhbGciOiJSUzI1NiJ9...",
"scope": "openid profile email offline_access"
}4. Use the Access Token
The access token works with the authenticated Customer API endpoints:
curl -X GET "https://edge.tiquo.app/api/client/v1/profile" \
-H "Authorization: Bearer eyJhbGciOiJSUzI1NiJ9..."Supported Grant Types
| Grant Type | Description |
|---|---|
authorization_code | Standard authorization code flow (with optional PKCE) |
refresh_token | Exchange a refresh token for new tokens |
Scopes
| Scope | Description |
|---|---|
openid | Required for OIDC. Returns an ID token. |
profile | Includes name and profile information in the ID token |
email | Includes email address in the ID token |
offline_access | Requests a refresh token so the application can renew access after the access token expires |
PKCE Support
Tiquo supports Proof Key for Code Exchange (PKCE) using the S256 challenge method. PKCE is recommended for all clients and is required for public clients (like mobile apps and single-page applications) that cannot securely store a client secret.
To use PKCE:
- Generate a random
code_verifier(43-128 characters, URL-safe) - Compute the
code_challengeas the Base64-URL-encoded SHA-256 hash of the verifier - Include
code_challengeandcode_challenge_method=S256in the authorization request - Include the original
code_verifierin the token exchange request
Token Refresh
Refresh tokens are issued only when the original authorization request includes the offline_access scope. If your application does not request that scope, omit refresh-token handling.
To get a new access token using a refresh token:
curl -X POST "https://edge.tiquo.app/api/auth/oauth2/token" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=refresh_token" \
-d "refresh_token=rt_xxx..." \
-d "client_id=your_client_id" \
-d "client_secret=your_client_secret"Refresh tokens are rotated on each use. Always store and use the new refresh token from the response.
UserInfo Endpoint
Retrieve the authenticated user's claims:
curl -X GET "https://edge.tiquo.app/api/auth/oauth2/userinfo" \
-H "Authorization: Bearer eyJhbGciOiJSUzI1NiJ9..."Response:
{
"sub": "user_abc123",
"email": "customer@example.com",
"name": "John Doe"
}JWKS (Token Verification)
To verify JWT tokens yourself, fetch the public keys from the JWKS endpoint:
curl "https://edge.tiquo.app/api/auth/jwks"The response contains the RSA public key(s) in JWK format. Tokens are signed with RS256.
Token Details
| Token | Algorithm | Lifetime | Issuer | Audience |
|---|---|---|---|---|
| Access token | RS256 | 1 hour | https://auth.tiquo.app | tiquo-client-api |
| ID token | RS256 | 10 hours | https://auth.tiquo.app | Your client ID |
| Refresh token | N/A | 30 days | N/A | N/A |
Access Token Claims
{
"sub": "user_abc123",
"email": "customer@example.com",
"token_source": "oauth",
"organization_id": "org_xyz",
"org_customer_id": "cust_456",
"customer_number": "CUST-000001",
"client_id": "your_client_id",
"scope": "openid profile email offline_access",
"iss": "https://auth.tiquo.app",
"aud": "tiquo-client-api",
"exp": 1706580000,
"iat": 1706576400
}Note that OAuth tokens include the client_id and scope claims, which are not present in DOM Package tokens.
ID Token Claims
The ID token is returned when the openid scope is requested. Treat the claims returned by the provider as the authoritative claim set for the signed-in customer; do not assume that requesting an additional scope will expose a particular field unless that field is present in the returned token or UserInfo response.
Native Mobile App Integration
iOS (Swift)
Use ASWebAuthenticationSession to handle the OAuth flow in iOS:
import AuthenticationServices
let authURL = URL(string: "https://edge.tiquo.app/api/auth/oauth2/authorize?client_id=\(clientId)&response_type=code&redirect_uri=myapp://callback&scope=openid%20profile%20email%20offline_access&code_challenge=\(codeChallenge)&code_challenge_method=S256")!
let session = ASWebAuthenticationSession(
url: authURL,
callbackURLScheme: "myapp"
) { callbackURL, error in
guard let url = callbackURL,
let code = URLComponents(url: url, resolvingAgainstBaseURL: false)?
.queryItems?.first(where: { $0.name == "code" })?.value
else { return }
// Exchange the code for tokens
exchangeCodeForTokens(code: code, codeVerifier: codeVerifier)
}
session.presentationContextProvider = self
session.start()Android (Kotlin)
Use Custom Tabs or AppAuth for the OAuth flow:
val authUri = Uri.parse("https://edge.tiquo.app/api/auth/oauth2/authorize")
.buildUpon()
.appendQueryParameter("client_id", clientId)
.appendQueryParameter("response_type", "code")
.appendQueryParameter("redirect_uri", "myapp://callback")
.appendQueryParameter("scope", "openid profile email offline_access")
.appendQueryParameter("code_challenge", codeChallenge)
.appendQueryParameter("code_challenge_method", "S256")
.build()
val customTabsIntent = CustomTabsIntent.Builder().build()
customTabsIntent.launchUrl(context, authUri)How It Works with the Customer API
The OAuth flow issues the same type of JWT access tokens as the DOM Package. Once you have an access token, you use it with the Customer API in exactly the same way:
- Register an OAuth client under Settings > Identity Provider (IDP) > OAuth Clients and configure its redirect URIs
- Redirect the customer to the authorization endpoint
- The customer signs in (via email OTP on the Tiquo sign-in page)
- Tiquo redirects back to your app with an authorization code
- Your app exchanges the code for an access token, ID token, and—when
offline_accesswas requested—a refresh token - Use the access token with Customer API endpoints (
/profile,/orders,/bookings,/enquiries) - When the access token expires, use the refresh token to get a new pair
The key difference from the DOM Package is that OAuth uses a redirect-based flow, while the DOM Package handles everything in-page. Choose based on your platform and requirements.