Skip to content

Typebot Account Model Field Mismatch with Keycloak Token Response #2085

@Moreira4568

Description

@Moreira4568

Describe the bug

Typebot’s integration with Keycloak fails because the fields expected by the Typebot Account model do not fully match the standard OAuth/OpenID Connect token response provided by Keycloak.

Specifically, Typebot expects an expires_at field (representing an absolute timestamp) and a refresh_token_expires_in field, whereas Keycloak returns expires_in (a duration in seconds) and refresh_expires_in.

In addition, the presence of unrecognized fields (such as not-before-policy) completely blocks the login process, forcing developers to implement custom transformations to achieve compatibility.


To Reproduce
Steps to reproduce the behavior:

  1. Integrate Typebot authentication using Keycloak as the OpenID Connect provider.
  2. Notice the mismatched fields:
    • Typebot expects expires_at, but Keycloak returns expires_in (duration in seconds).
    • Typebot expects refresh_token_expires_in, but Keycloak returns refresh_expires_in.
    • Extra fields, such as not-before-policy, are present in the token response.
  3. The login process fails, blocking authentication entirely.

Expected behavior
It is expected that:

  • Typebot accepts Keycloak’s standard token response by allowing the use of expires_in (duration in seconds) instead of requiring an absolute epoch time for expires_at.
  • The refresh_expires_in field from Keycloak is mapped to the expected refresh_token_expires_in field in Typebot.
  • The oauth_token_secret and oauth_token fields are clarified as optional or can be omitted when integrating with Keycloak.
  • The system gracefully handles extra or unexpected fields in the token response without blocking the login process, thereby reducing integration complexity and improving the user experience.

Code Snippets & Models

  1. Typebot Model (Prisma Schema)
// schema.prisma
model Account {
  id                       String  @id @default(cuid())
  userId                   String
  type                     String
  provider                 String
  providerAccountId        String
  refresh_token            String? @db.Text
  access_token             String? @db.Text
  expires_at               Int?
  token_type               String?
  scope                    String?
  id_token                 String? @db.Text
  session_state            String?
  oauth_token_secret       String?
  oauth_token              String?
  refresh_token_expires_in Int?
  user                     User    @relation(fields: [userId], references: [id], onDelete: Cascade)

  @@unique([provider, providerAccountId])
  @@index([userId])
}
  1. Keycloak Token Response
public class AccessTokenResponse {
    @JsonProperty("access_token")
    protected String token;
    @JsonProperty("expires_in")
    protected long expiresIn;
    @JsonProperty("refresh_expires_in")
    protected long refreshExpiresIn;
    @JsonProperty("refresh_token")
    protected String refreshToken;
    @JsonProperty("token_type")
    protected String tokenType;
    @JsonProperty("id_token")
    protected String idToken;
    @JsonProperty("not-before-policy")
    protected int notBeforePolicy;
    @JsonProperty("session_state")
    protected String sessionState;
    protected Map<String, Object> otherClaims = new HashMap();
    @JsonProperty("scope")
    protected String scope;
    @JsonProperty("error")
    protected String error;
    @JsonProperty("error_description")
    protected String errorDescription;
    @JsonProperty("error_uri")
    protected String errorUri;
}

Tool Versions & Environment
For context, here are the versions used in the environment where the issue was identified:

  • Typebot Builder: 3.5.0
  • Keycloak Version: 26.0.6

Metadata

Metadata

Assignees

No one assigned

    Labels

    Bug 🐛Something isn't working

    Projects

    Status

    Deployed 🎉

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions