Web Application Flow
You can enable other users to authorize your Auth0 app
You can integrate with Portal to authentication users. User authenticating with your Portal Apps will follow the flow:
Overview of the Web application flow
- Users are redirected to request their Portal Identity.
- Users are redirected back to your app by Portal.
- Your app exchanges the authorization code for tokens and uses them to access the API.
1. Request User Portal Identity
GET https://auth.portalgaming.com/authorize
The following parameters are used with this API.
PARAMETER NAME | TYPE | DESCRIPTION |
---|---|---|
redirect_uri (required) | string | The URL in your application where users will be sent after authorization. See details below about redirect urls. |
audience | string | https://api.portalgaming.com |
response_type | string | Indicates which OAuth 2.0 flow you want to use. Use code for Authorization Code Grant Flow.id_token code token |
scope | string | A space-delimited list of scopes. If not provided, scope defaults to an empty list for users that have not authorized any scopes for the application. |
state | string | An unguessable random string. It is used to protect against cross-site request forgery attacks. |
code_challenge | string | A PKCE parameter, a random secret for each request you make. This must be a string with at least 22 characters. |
code_challenge_method | string | Method used to generate the challenge. The PKCE spec defines two methods, S256 and plain, however, Portal only supports S256 since the latter is discouraged. |
PCKE is required for all authorization code flow requests.
2. Exchange users authorization code for a token
Providing the user accepts your request, Portal redirects back to your site with a temporary code in a code parameter as well as the state you provided in the previous step in a state parameter. The temporary code will expire after 10 minutes. If the states don't match, then a third party created the request, and you should abort the process.
POST https://auth.portalgaming.com/oauth/token
curl --location --request POST 'https://auth.portalgaming.com/oauth/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data "grant_type=authorization_code&code=$AUTH_CODE&redirect_uri=http://localhost:3001/auth/callback&code_verifier=$CODE_VERIFIER&audience=https://api.portalgaming.com&client_id=$CLIENT_ID"
const body = new URLSearchParams({
grant_type: 'authorization_code',
code: AUTH_CODE,
redirect_uri: REDIRECT_URI,
code_verifier: codeVerifier,
audience: CLIENT_ID,
client_id: CLIENT_ID,
});
const response = await fetch(TOKEN_URL, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: body.toString(),
});
payload = {
'grant_type': 'authorization_code',
'code': auth_code,
'redirect_uri': REDIRECT_URI,
'code_verifier': code_verifier,
'audience': CLIENT_ID,
'client_id': CLIENT_ID,
}
headers = {
'Content-Type': 'application/x-www-form-urlencoded',
}
response = requests.post(TOKEN_URL, data=urllib.parse.urlencode(payload), headers=headers)
This endpoint takes the following input parameters.
PARAMETER NAME | TYPE | DESCRIPTION |
---|---|---|
client_id | string | This should be the UUID of your Portal App |
grant_type | string | authorization_code |
code | string | The authorization code returned from the /authorize callback |
redirect_uri | string | The redirect_uri specified when authorizing the user |
code_verifier | string | Optional. When using PKCE with a public client, code_verifier is required. |
audience | string | The audience the token is valid for. |
Response
By default, the response takes the following form:
{
"access_token": "U-LAkRFclMaTyHWMlVbArD2wkpQGcUIyY-YlSjWkayF",
"expires_in": 86400,
"id_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImYyNjJhMzIxNDIxM2QxOTRjOTI5OTFkNjczNWIxNTNiIn0.eyJzdWIiOiIwNDAwNTBjMS02M2JiLTQxMjYtOGQ2YS05NzVlZjBhYzViYWQiLCJhdF9oYXNoIjoiNjJRSzdmSnF4MVplNVIyU01xU2NPZyIsImF1ZCI6ImNjNDk3ODY0LTJkZDItNGNhOC05NTg0LTAwNzRiYTMyMWJiMSIsImV4cCI6MTcyMjAxNjI1OSwiaWF0IjoxNzIyMDEyNjU5LCJpc3MiOiJodHRwczovL3BvcnRhbC1wbGF0Zm9ybS1hcGkuZGV2LnN1cGVyZHVwZXJkZXYueHl6In0.rpI0Z_ppE7JWId1jspqgmravp-EDGsMOujdUoUPFLqcHdi7Qa4B5TbcMJsRkH7XyBx1RUV-DR05hoa65TLPqC4THvqiqeM2iIIA2GSFU4wJC8Dy8bK5aGJC3zT1haZocukbBLJYCF42VOGl_Nfct_pGr3LHeetQRztgjSHQ-oo9QZY4XpjlQW3Adx-I2vsj8mih5UblLfOznyFB41nbw4TVJvgUk7NhlkTBKuJJEILSkDlAa4hSYtoXfNmVMrxke-1W9BSADwTGUmcMK0hjYhGUiN6vzLZErJyVuP8y7eIM-62dwg1mfw3UKR2P_0IlZ0xoAEch85063IwXZVGULxVuT7zZimliwFtY4xXcQLQ7-m4jJG0tpQceTwk23lUsJ2q-4enDRdbOkf03zUpIWxxC9YK1Q2amJvL-_DA2uu-ViOUPOgcl5PMMLaBjq2jFTaR6bGCRCQ8ag4uBP8-0ZJ9LN3vUZeZ7eI5F9up_24LjU6lBPjzMwAKpGXlJnckOb",
"scope": "openid",
"token_type": "Bearer"
}
3. Use the access token to access the API
curl 'https://api.portalgaming.com/v1/users/me' \
--header 'Authorization: Bearer U-LAkRFclMaTyHWMlVbArD2wkpQGcUIyY-YlSjWkayF'
Response
{
"data": {
"id": "040050c1-63bb-4126-8d6a-975ef0ac5bad",
"email": "[email protected]",
"status": "Verified",
"profilePictureUrl": null,
"profile": {
"isPasswordRecoverySet": true,
"id": "75c371a5-c2d7-455e-bd44-f7aee35dcad3",
"externalId": "pla_e4c51972-2670-4c27-a9c5-2dc11e697ffc",
}
},
"status": 200,
"error": null
}
Web Application Flow Basic Example
Prerequisites
- Node.js and npm: Ensure you have Node.js and npm installed.
- Create an OAuth Client: Register your application with your Portal Platform Identity Service to get the CLIENT_ID and CLIENT_SECRET.
Registering your Portal App
First you'll need to register your application.
Every registered OAuth app is assigned a unique Client ID and Client Secret. The client secret is used to get an access token for the signed-in user. You must include the client secret in your native application, however web applications should not leak this value.
You can fill out every other piece of information however you like, except the Authorization callback URL. This is the most important piece to securely setting up your application. It's the callback URL that GitHub returns the user to after successful authentication. Ownership of that URL is what ensures that users sign into your app, instead of leaking tokens to an attacker.
For example, we will have our development server running locally at http://localhost:3001
so we set our redirectUris
to http://localhost:3001/auth/callback
.
Step 1: Set Up the Project
- Create a new directory for your project:
mkdir portal-oauth-demo
cd portal-oauth-demo
- Initialize a new Node.js project:
npm init -y
- Install the required packages:
npm install express axios querystring dotenv
Step 2: Create Environment Variables
CLIENT_ID=your_client_id
CLIENT_SECRET=your_client_secret
REDIRECT_URI=http://localhost:3000/auth/callback
AUTHORIZATION_URL=https://auth.portalgaming.com/authorize
TOKEN_URL=https://auth.portalgaming.com/oauth/token
Step 3: Set Up the Express Server
const express = require("express");
const axios = require("axios");
const querystring = require("querystring");
const { randomBytes, createHash } = require("node:crypto");
require("dotenv").config();
const app = express();
const PORT = 3001;
const codeVerifiers = {};
const { CLIENT_ID, CLIENT_SECRET, REDIRECT_URI, AUTHORIZATION_URL, TOKEN_URL } =
process.env;
function generatePKCEPair() {
// Total of 44 characters (1 Bytes = 2 char) (standard states that: 43 chars <= verifier <= 128 chars)
const NUM_OF_BYTES = 22;
const HASH_ALG = "sha256";
const randomVerifier = randomBytes(NUM_OF_BYTES).toString("hex");
const hash = createHash(HASH_ALG).update(randomVerifier).digest("base64");
const challenge = hash
.replace(/\+/g, "-")
.replace(/\//g, "_")
.replace(/=+$/, ""); // Clean base64 to make it URL safe
return { verifier: randomVerifier, challenge };
}
// Step 1: Redirect to Authorization Server
app.get("/login", async (req, res) => {
const challenge = generatePKCEPair();
// Store the code verifier for later use
codeVerifiers[req.sessionID] = challenge.verifier;
const params = querystring.stringify({
response_type: "code",
client_id: CLIENT_ID,
redirect_uri: REDIRECT_URI,
scope: "openid profile",
code_challenge: challenge.challenge,
code_challenge_method: "S256",
});
res.redirect(`${AUTHORIZATION_URL}?${params}`);
});
// Step 2: Handle the Callback from the Authorization Server
app.get("/auth/callback", async (req, res) => {
const { code, error, error_description } = req.query;
const codeVerifier = codeVerifiers[req.sessionID];
if (error) {
return res.json({ error, error_description });
}
if (!codeVerifier) {
return res.status(400).send("Missing code verifier");
}
try {
// Step 3: Exchange Authorization Code for Tokens
const response = await axios.post(
TOKEN_URL,
querystring.stringify({
grant_type: "authorization_code",
code,
redirect_uri: REDIRECT_URI,
client_id: CLIENT_ID,
client_secret: CLIENT_SECRET,
code_verifier: codeVerifier,
}),
{
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
},
);
const { access_token, id_token } = response.data;
// Step 4: Decode the ID Token (optional)
const userInfo = decodeJwt(id_token);
res.json({ access_token, id_token, userInfo });
} catch (error) {
res.status(500).send(error.response.data);
} finally {
// Clean up the code verifier
delete codeVerifiers[req.sessionID];
}
});
// Utility function to decode JWT (without verification)
function decodeJwt(token) {
const [header, payload] = token
.split(".")
.slice(0, 2)
.map((part) => Buffer.from(part, "base64").toString("utf8"));
return {
header: JSON.parse(header),
payload: JSON.parse(payload),
};
}
app.listen(PORT, () => {
console.log(`Server is running on http://localhost:${PORT}`);
});
Step 4: Run the Server
node index.js
Updated 19 days ago