Skip to content
GitHub

Guest Login

Complete guide for implementing guest authentication using Guardian’s /v1/guest/login endpoint.

Guardian implements guest authentication to allow anonymous or unauthenticated users to access your application with limited permissions. Guest users are identified by a device or app-instance derived identifier, which can optionally be encrypted using AES-CBC encryption for enhanced security.

The guest login flow is a single-step process:

  1. Client sends a guest identifier: Client provides a guest identifier (optionally encrypted), client ID, and requested scopes
  2. Guardian validates and processes: Guardian validates the request, decrypts the identifier if encrypted, validates scopes, and generates an access token
  3. Token response: Guardian returns an access token in the response body and as an HTTP-only cookie

Key Features:

  • Optional Encryption: Guest identifiers can be encrypted using AES-CBC algorithm with a shared secret key
  • Scope Validation: Scopes are validated against both guest allowed scopes and client scopes
  • Cookie Support: Access token is automatically set as an HTTP-only cookie for seamless integration
  • No User Service Required: Guest login does not require user service integration - it works independently

Before implementing guest authentication, ensure you have:

  1. Guardian Tenant: A configured tenant ID

  2. OAuth Client: A registered client ID for your application

  3. Guest Configuration: Guest configuration set up in the database (encryption settings, allowed scopes)

Guest authentication configuration is tenant-specific and stored in the guest_config database table. See Guest Configuration for the complete schema, field descriptions, and encryption details.

Endpoint: POST /v1/guest/login

Purpose: Authenticates a guest user and returns an access token. The guest identifier can be encrypted or plain text based on tenant configuration.

Headers:

  • Content-Type: application/json
  • tenant-id: <your-tenant-id> (required)

Request Body:

{
  "guest_identifier": "QwnZ/2k+mpCm27nFOqb95g==",
  "client_id": "my-client-id",
  "scopes": ["profile", "email", "phone"]
}

Request Parameters:

ParameterTypeRequiredDescription
guest_identifierstringYesDevice or app-instance derived identifier. Must be encrypted if tenant configuration is_encrypted is true, otherwise plain text
client_idstringYesGuardian OAuth client ID. This must be created in Guardian before use
scopesarray[string]YesArray of OAuth scopes to request (e.g., [“profile”, “email”, “phone”])

Response: 200 OK

{
  "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
  "token_type": "Bearer",
  "expires_in": 900
}

Response Parameters:

ParameterTypeDescription
access_tokenstringJWT access token for API authentication
token_typestringToken type. Always “Bearer”
expires_inintegerAccess token expiration time in seconds

Response Headers:

The access token is also returned as an HttpOnly cookie in the Set-Cookie header:

Set-Cookie: AT=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...; Path=/; HttpOnly; Secure; SameSite=Strict

Error Responses:

CodeStatusMessageWhenResolution
invalid_request400guestIdentifier cannot be null or emptyMissing or empty guest_identifierProvide valid guest_identifier
invalid_request400clientId cannot be null or emptyMissing or empty client_idProvide valid client_id
invalid_request400scopes cannot be null or emptyMissing or empty scopes arrayProvide at least one scope
invalid_guest_identifier400Invalid guest identifierDecryption failed or invalid encrypted formatVerify encryption/decryption logic and secret key
invalid_scope400Invalid scope <scope>Scope not in guest allowed scopes or client scopesUse only allowed scopes
client_not_found404Client not foundClient ID does not existVerify client_id exists in Guardian
client_not_found404Client not foundClient ID does not exist for tenantVerify client_id exists for the specified tenant
type: object
required:
  - guest_identifier
  - client_id
  - scopes

properties:
  guest_identifier:
    type: string
    description: Device- or app-instance-derived identifier. Must be encrypted if tenant configuration is_encrypted is true, otherwise plain text
    example: "QwnZ/2k+mpCm27nFOqb95g=="

  client_id:
    type: string
    description: Guardian OAuth client ID. This must be created in Guardian before use
    example: "my-client-id"

  scopes:
    type: array
    items:
      type: string
    description: Array of OAuth scopes to request
    example: ["profile", "email", "phone"]
type: object
properties:
  access_token:
    type: string
    description: JWT access token for API authentication

  token_type:
    type: string
    example: "Bearer"
    description: Token type. Always "Bearer"

  expires_in:
    type: integer
    description: Access token expiration time in seconds

For complete request and response schemas, refer to the Guardian API Specification.

Guest Login with Encrypted Identifier:

curl --location 'http://localhost:8080/v1/guest/login' \
--header 'Content-Type: application/json' \
--header 'tenant-id: tenant1' \
--data '{
    "guest_identifier": "QwnZ/2k+mpCm27nFOqb95g==",
    "client_id": "my-client-id",
    "scopes": ["profile", "email", "phone"]
}'

Guest Login with Plain Text Identifier (when is_encrypted is false):

curl --location 'http://localhost:8080/v1/guest/login' \
--header 'Content-Type: application/json' \
--header 'tenant-id: tenant2' \
--data '{
    "guest_identifier": "test123",
    "client_id": "my-client-id",
    "scopes": ["profile"]
}'
┌─────────┐                    ┌──────────┐
│ Client  │                    │ Guardian │
│         │                    │          │
└────┬────┘                    └────┬─────┘
     │                              │
     │ 1. POST /v1/guest/login      │
     │─────────────────────────────>│
     │ {guest_identifier,           │
     │  client_id, scopes}          │
     │                              │
     │                              │ 2. Validate request
     │                              │    (guest_identifier, client_id, scopes)
     │                              │
     │                              │ 3. Get guest config
     │                              │    (is_encrypted, secret_key, allowed_scopes)
     │                              │
     │                              │ 4. Decrypt guest_identifier
     │                              │    (if is_encrypted is true)
     │                              │
     │                              │ 5. Validate scopes
     │                              │    - Check against guest allowed_scopes
     │                              │    - Check against client scopes
     │                              │
     │                              │ 6. Generate access token
     │                              │    (JWT with guest_identifier as subject)
     │                              │
     │                              │ 7. Set access token cookie
     │                              │
     │ 8. Return access token       │
     │<─────────────────────────────│
     │ {access_token, token_type,   │
     │  expires_in}                 │
     │ + Set-Cookie header          │
     │                              │

The access token returned by guest login is a JWT (JSON Web Token) with the following claims:

ClaimDescription
subGuest identifier (decrypted if encryption was used)
scopeSpace-separated list of granted scopes
tenant_idTenant identifier
client_idClient ID used for authentication
expToken expiration timestamp
iatToken issuance timestamp
amrAuthentication method reference (empty array for guest login)

Problem: Request fails with “Invalid guest identifier” error

Possible Causes:

  • Decryption failed due to incorrect secret key
  • Encrypted identifier format is invalid (not Base64)
  • Encryption algorithm or parameters don’t match Guardian’s implementation
  • Plain text identifier provided when encryption is required

Solutions:

  • Verify secret_key in guest_config matches the key used for encryption
  • Ensure encrypted identifier is Base64-encoded
  • Check that encryption uses AES-CBC with zero IV
  • Verify padding is correct (plain text must be block-aligned)
  • If is_encrypted is true, ensure you’re sending encrypted identifier
  • If is_encrypted is false, ensure you’re sending plain text identifier

Problem: Request fails with “Invalid scope” error

Possible Causes:

  • Requested scope is not in guest allowed_scopes
  • Requested scope is not assigned to the client
  • Scope name is misspelled

Solutions:

  • Check allowed_scopes in guest_config table
  • Verify client has the requested scopes assigned in client_scope table
  • Ensure scope names match exactly (case-sensitive)
  • Use only scopes that are both in guest allowed scopes and client scopes

Problem: Request fails with “Client not found” error

Possible Causes:

  • Client ID doesn’t exist in Guardian
  • Client ID belongs to a different tenant
  • Client ID is misspelled

Solutions:

  • Verify client exists in client table for the specified tenant
  • Check that client_id matches exactly (case-sensitive)
  • Ensure client is created before using it for guest login

”scopes cannot be null or empty” Error

Section titled “”scopes cannot be null or empty” Error”

Problem: Request fails with “scopes cannot be null or empty” error

Solutions:

  • Provide at least one scope in the scopes array
  • Ensure scopes is not null or empty array
  • Verify JSON format is correct

Problem: Access token cookie is not being set in browser

Possible Causes:

  • Cookie settings (domain, path, secure, sameSite) don’t match your application
  • Browser is blocking cookies
  • HTTPS is required but using HTTP

Solutions:

  • Check cookie configuration in token_config table
  • Verify cookie_domain matches your application domain
  • Ensure cookie_secure is set appropriately (true for HTTPS, false for HTTP in development)
  • Check browser console for cookie-related errors
  • Use HTTPS in production environments
  1. Encryption: Enable encryption for guest identifiers in production to protect user privacy

  2. Secret Key Management: Store secret keys securely and rotate them periodically

  3. Scope Limitation: Limit guest allowed scopes to only what’s necessary for anonymous access

  4. Token Expiration: Set appropriate access token expiration time (default: 900 seconds / 15 minutes)

  5. HTTPS: Use HTTPS for all API calls in production to protect tokens in transit

  6. Cookie Security: Configure secure cookie settings (HttpOnly, Secure, SameSite) appropriately

  7. Identifier Generation: Generate unique, non-guessable guest identifiers for each device/app instance

  8. Scope Validation: Always validate scopes on both client and server side

  9. Error Handling: Implement proper error handling and user feedback for authentication failures

  10. Token Storage: Store tokens securely (HttpOnly cookies or secure storage) and never expose them in client-side code or URLs