Authentication
This guide will help you understand how to handle authentication in Lens.
The Lens API uses authentication roles to define different levels of access and interaction:
Account Owner: An end-user who owns a Lens Account.
Account Manager: An end-user managing a Lens Account, either their own or one they have been delegated. See the Account Managers guide for more information.
Onboarding User: A end-user without a Lens Account, limited to features related to onboarding, such as creating an account.
Builder: A developer role used to authenticate and access configuration and management features.
Log In to Lens
To log in to Lens, end-user roles such as Account Owner, Account Manager, or Onboarding User need to know the EVM address of the App they want to connect to. The Builder role does not require an app address for authentication.
Unless you are using the Builder role, you MUST specify the App address you want to authenticate with. For more details, see the Apps section to learn how to create an App.
- GraphQL
- React
- TypeScript
First, generate an authentication challenge.
If you are making this request from a non-browser environment, ensure that the HTTP Origin header is set to the correct value for your application's domain.
The challenge response will contain the id and the text of the challenge message.
Response
{ "data": { "challenge": { "id": "<challenge-id>", "text": "<origin-domain> wants you to sign in with your Ethereum account…" } }}
The challenge text is a Sign-In with Ethereum (SIWE) message used to verify the ownership of the signer address. It is issued only if the signer address is the Account itself or an Account Manager for the given Account.
List Available Accounts
Often, when you are about to log in with an Account, you may want to list the available Accounts for the user's wallet.
- GraphQL
- React
- TypeScript
You can use the paginated accountsAvailable query to list the Accounts owned or managed by a given address.
Continue with the Pagination guide for more information on how to handle paginated results.
See the Account Manager guide for more information on how to manage accounts.
Manage Sessions
Once you have successfully authenticated, you can manage your authenticated session by:
Refreshing your authentication tokens
Getting details about the current session
Listing all authenticated sessions
Tokens Refresh
- GraphQL
- React
- TypeScript
You can refresh your authentication tokens by calling the refreshAuthentication mutation.
Get Current Session
- GraphQL
- React
- TypeScript
You can get details about the current session by calling the currentSession query.
You MUST be authenticated as Account Owner or Account Manager to make this request.
List Authenticated Sessions
- GraphQL
- React
- TypeScript
You can list all your active sessions by calling the paginated authenticatedSessions query.
You MUST be authenticated as Account Owner or Account Manager to make this request.
See the Pagination guide for more information on how to handle paginated results.
Log Out
- GraphQL
- React
- TypeScript
You can revoke any authenticated session by calling the revokeAuthentication mutation.
You MUST be authenticated as Account Owner or Account Manager to make this request.
This will invalidate the Refresh Token for the given authenticated session. Any attempt to use them will result in forbidden error. Any issued Access Tokens will remain valid for the remainder of their short lifetime.
Get Last Logged-In Account
- GraphQL
- React
- TypeScript
Coming soon
Advanced Topics
Authentication Tokens
Lens API uses JSON Web Tokens (JWT) as format for Token-Based authentication.
On successful authentication, Lens API issues three tokens:
Access Token
ID Token
Refresh Token
Lens JWTs are signed with the RS256 algorithm and can be verified using JSON Web Key Sets (JWKS) from the /.well-known/jwks.json endpoint on the corresponding Lens API environment (e.g., <coming-this-week>/.well-known/jwks.json for testnet).
Signing keys could be rotated at any time. Make sure to cache the JWKS and update it periodically.
Access Token
Access Tokens are used to authenticate a user's identity when making requests to the Lens API.
The Access Token is required in the Authorization or x-access-token header for all authenticated requests to the Lens API.
Authorization: Bearer <access-token># orx-access-token: <access-token>
DO NOT share the Access Token with anyone. Keep it secure and confidential. If you are looking to identify a user's request on a backend service, use the ID Token instead.
Lens Access Tokens are valid for 10 minutes from the time of issuance.
Refresh Token
A Refresh Token is a credential artifact used to obtain a new authentication tokens triplet without user interaction. This allows for a shorter Access Token lifetime for security purposes without involving the user when the access token expires. You can request new authentication tokens until the refresh token is added to a denylist or expires.
DO NOT share the Refresh Token with anyone. Keep it secure and confidential, possibly on the client-side only. If you are looking to perform an operation in behalf of an Account, use the Account Manager feature instead.
Lens Refresh Tokens are valid for 7 days from the time of issuance.
ID Token
The ID Token is used to verify the user's identity on consumer's side. It contains a set of claims about the user and is signed by the Lens API.
Lens ID Tokens are valid for 10 minutes from the time of issuance, same as the Access Token.
You can use the ID Token to verify the user's identity on a backend service like described in the Consume Lens ID Tokens section.
Consume Lens ID Tokens
As briefly mentioned earlier, Lens ID Tokens can be used to verify's user identity on a backend service.
Lens ID Tokens are issued with the following claims:
Claim | Description | |
---|---|---|
sub | Subject - the signedBy address used to sign the Authentication Challenge. This could be the Account or an Account Manager for it. Example: 0xC47Cccc2bf4CF2635a817C01c6A6d965045b06e6. | |
iss | Issuer - the Lens API endpoint that issued the token. Typically: <coming-this-week>. | |
aud | Audience - the Lens App address that the token is intended for. Example: 0x00004747f7a56EE7Af7237220c960a7D06232626. | |
iat | Issued At - the timestamp when the token was issued. | |
exp | Expiration - the timestamp indicating when the token will expire. This can be used to determine if the token is still valid. | |
sid | Session ID - the unique identifier of the session that the token was issued for. | |
act | Optional claim that allows the token to act on behalf of another Account. This is useful for Account Managers to specify the Account address they can act on behalf of. | |
tag:lens.dev,2024:sponsored | Custom claim that indicates the authenticated session is enabled for sponsored transactions. | |
tag:lens.dev,2024:role | Custom claim that indicates the role of the authenticated session. Possible values are ACCOUNT_OWNER, ACCOUNT_MANAGER, ONBOARDING_USER, and BUILDER. |
A typical use case is to use Lens issued ID Token to verify the legitimacy of user's request before issuing your app specific credentials. The following diagram illustrates this flow:
Below is an example of a Next.js middleware that demonstrates how to verify a Lens ID Token using the popular jose library:
middleware.ts
import { NextResponse } from "next/server";import { jwtVerify, createRemoteJWKSet } from "jose";
// Get JWKS URI from environment variablesconst jwksUri = process.env.NEXT_PUBLIC_JWKS_URI;const JWKS = createRemoteJWKSet(new URL(jwksUri));
export async function middleware(req) { const token = req.headers.get("authorization")?.split(" ")[1];
if (!token) { return new NextResponse( JSON.stringify({ error: "Authorization token missing" }), { status: 401, headers: { "Content-Type": "application/json" }, } ); }
try { // Verify the JWT using the JWKS const { payload } = await jwtVerify(token, JWKS);
// Optionally, attach the payload to the request req.user = payload;
// Proceed to the API route return NextResponse.next(); } catch (error) { console.error("JWT verification failed:", error); return new NextResponse( JSON.stringify({ error: "Invalid or expired token" }), { status: 401, headers: { "Content-Type": "application/json" }, } ); }}
export const config = { matcher: ["/api/:path*"],};
The example works under the following assumptions:
The Lens ID Token is passed in the Authorization header as a Bearer token (e.g., Authorization: Bearer <ID Token>).
The JWKS URI is available in the NEXT_PUBLIC_JWKS_URI environment variable.
Your API routes are located under the /api path.
Adapt it to your specific use case as needed.
You can now use the req.user object in your API routes to access the user's identity.
Example API Route
export default function handler(req, res) { // The JWT payload will be available as req.user if the token is valid if (req.user) { return res.status(200).json({ message: "Success", user: req.user }); } else { return res.status(401).json({ error: "Unauthorized" }); }}