Keycloakとは、ログイン画面・ユーザー管理・シングルサインオン(SSO)・トークン発行をまとめて引き受けるオープンソースの認証サーバー(IdP)です。 アプリは自分でパスワードを扱わず、OpenID Connect(OIDC)でKeycloakにログインを任せ、受け取ったアクセストークン(JWT)を検証するだけで済みます。

この記事では、2026年10月時点の Keycloak 26.7系(公式Getting Startedの記載は26.7.5)を前提に、用語の一覧 → PKCE付き認可コードフロー → 起動(開発・本番) → 管理画面とkcadmでの設定 → APIでのJWT検証を一気通貫で解説します。上位の解説記事では開発モード(start-dev)までのものが多いため、本番の起動オプション(DB・hostname・TLS・リバースプロキシ)と判断表まで載せました。

検証について:この記事の作成環境ではKeycloak本体(公式配布・コンテナイメージ)を入手できなかったため、起動・管理画面・kcadmの手順は公式ドキュメントに沿って記載し、未実行です。一方、JWT検証コードは、Keycloakと同じクレーム構造のトークンと JWKS をローカルで自作し、Python(PyJWT 2.15.1)と Node(jose 6.2.12)で実行して、期限切れ・aud違い・改ざんなど8パターンの結果を載せています。OAuth 2.0とOIDCの違いそのものは別記事で扱っているので、ここではKeycloakの設定に絞ります。

Keycloak入門の早見表

やりたいこと 方法(Keycloak 26.x)
開発用に起動 bin/kc.sh start-dev(HTTP 8080、DBは組み込み)
コンテナで開発用に起動 docker run -p 8080:8080 -e KC_BOOTSTRAP_ADMIN_USERNAME=admin -e KC_BOOTSTRAP_ADMIN_PASSWORD=admin quay.io/keycloak/keycloak:26.7.5 start-dev
本番用に起動 bin/kc.sh start --hostname=https://auth.example.com --db=postgres ...(HTTPS必須)
最初の管理ユーザー 環境変数 KC_BOOTSTRAP_ADMIN_USERNAME / KC_BOOTSTRAP_ADMIN_PASSWORD
設定の入口(Discovery) /realms/{realm}/.well-known/openid-configuration
ログイン(認可エンドポイント) /realms/{realm}/protocol/openid-connect/auth
トークン取得 /realms/{realm}/protocol/openid-connect/token
公開鍵(JWKS) /realms/{realm}/protocol/openid-connect/certs
トークンの iss https://{hostname}/realms/{realm}
ロールの場所(JWT内) Realmロール:realm_access.roles/Clientロール:resource_access.{client}.roles
aud にAPI名を入れる Client Scope に Audience マッパーを追加
SPAのクライアント設定 Client authentication OFF(public)、Standard flow ON、PKCE S256
CLIで設定 bin/kcadm.sh config credentials ... → kcadm.sh create realms / clients / users

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「Keycloak入門|OIDCログインとJWT検証を最短で構築」

Keycloakの用語一覧

Keycloakの設定は「Realm(区画)の中に、Client(アプリ)・User・Role を作り、Client Scope と Mapper でトークンの中身を決める」という構造です。

用語 ひとことで 入門で押さえる点
Realm ユーザーやアプリをまとめる独立した区画 master は管理用。アプリ用には別のRealmを作る。iss に含まれる
Client Keycloakにログインを任せるアプリ client_id で識別。ブラウザだけで動くSPAは public、サーバー側アプリは confidential(クライアントシークレットあり)
User ログインする人 パスワード・属性・グループ・ロールを持つ
Group ユーザーのまとまり グループにロールを付けると所属ユーザーに継承される
Identity Provider / User Federation 外部IdP連携/既存台帳(LDAPなど)連携 ソーシャルログインや社内ディレクトリを使うとき
Realm Role Realm全体で使うロール JWTの realm_access.roles に入る
Client Role 特定のClient用のロール JWTの resource_access.{client_id}.roles に入る
Client Scope トークンに含める情報のセット profile・email・roles など。Clientに Default(常に付与)/Optional(scope 指定時のみ)で割り当てる
Mapper(Protocol Mapper) トークンにクレームを追加・変換する部品 ユーザー属性 → クレーム、Audience(aud の追加)など
Authentication Flow ログインの手順の定義 パスワード+ワンタイムパスワード(OTP)などを組み立てる

PKCE付き認可コードフローとKeycloakの設定の対応

ブラウザで動くアプリ(SPA)やスマホアプリは、PKCE付きの認可コードフローを使います。 PKCE(ピクシー)は、ログイン開始時に作った秘密の値(code_verifier)を、トークン交換のときに提示させる仕組みで、認可コードの横取りを防ぎます。

sequenceDiagram
    autonumber
    actor U as ユーザー
    participant W as order-web(public client)
    participant K as Keycloak(realm: myrealm)
    participant A as order-api(Resource Server)
    U->>W: ログインをクリック
    W->>W: code_verifier を生成し code_challenge = SHA256 を計算
    W->>K: /realms/myrealm/protocol/openid-connect/auth<br/>client_id, redirect_uri, scope=openid, state, code_challenge(S256)
    K->>U: ログイン画面(パスワード・MFA・外部IdP)
    U->>K: 認証
    K->>W: redirect_uri?code=...&state=...
    W->>K: /protocol/openid-connect/token<br/>code + code_verifier
    K->>W: access_token(JWT), id_token, refresh_token
    W->>A: Authorization: Bearer access_token
    A->>K: /protocol/openid-connect/certs(JWKSを取得しキャッシュ)
    A->>A: 署名・iss・aud・exp・realm_access.roles を検証
    A->>W: 200 OK(注文一覧)
図の番号 Keycloak側で効いている設定
3 Client の Valid redirect URIs(一致しないと Invalid parameter: redirect_uri)、PKCE Method = S256
4〜5 Realm の Authentication Flow、Identity Provider、パスワードポリシー
7 Client の Client authentication(publicならシークレット不要)、Web origins(ブラウザから呼ぶときのCORS)
8 Realm の Tokens(アクセストークンの有効期間、既定5分)、Client Scope と Mapper(中身)
10〜11 Realm の Keys(署名鍵。kid で識別)、aud は Audience マッパー

Keycloakを起動する(開発モードと本番モード)

start-dev は開発用の便利な既定値(HTTP有効・組み込みDB・キャッシュはローカル)で起動し、start は本番用にHTTPSとホスト名の設定を求めます。(以下は公式ドキュメントに沿った記載で、未実行です。)

開発モード

# ZIP版(展開したディレクトリで)
export KC_BOOTSTRAP_ADMIN_USERNAME=admin
export KC_BOOTSTRAP_ADMIN_PASSWORD=admin
bin/kc.sh start-dev

# コンテナ版
docker run -p 8080:8080 \
  -e KC_BOOTSTRAP_ADMIN_USERNAME=admin -e KC_BOOTSTRAP_ADMIN_PASSWORD=admin \
  quay.io/keycloak/keycloak:26.7.5 start-dev

http://localhost:8080/admin/ にアクセスし、上の管理ユーザーでログインします。KC_BOOTSTRAP_ADMIN_* は最初の一時的な管理ユーザーを作るためのもので、ログイン後に正式な管理ユーザーを作り直すことが推奨されています。

本番モード(DB・hostname・TLS)

# 1) 使うDBなどを焼き込んでビルド(起動を速くする)
bin/kc.sh build --db=postgres --health-enabled=true --metrics-enabled=true

# 2) 起動
bin/kc.sh start --optimized \
  --hostname=https://auth.example.com \
  --https-certificate-file=/etc/keycloak/tls.crt \
  --https-certificate-key-file=/etc/keycloak/tls.key \
  --db-url-host=db.internal --db-url-database=keycloak \
  --db-username=keycloak --db-password=change_me

同じ設定は conf/keycloak.conf に db-url-host=db.internal のように書くか、環境変数 KC_DB_URL_HOST=db.internal のように KC_ +大文字・アンダースコアで渡せます。

リバースプロキシでTLSを終端する構成では、証明書の2つのオプションの代わりに --proxy-headers=xforwarded --http-enabled=true を指定します。

オプション 意味 ポイント
--hostname 外部に公開するURL トークンの iss になる。APIの検証設定と完全に一致させる
--https-certificate-file / -key-file TLS証明書と秘密鍵 Keycloak自身でHTTPSを受ける場合
--proxy-headers xforwarded か forwarded プロキシが付けるヘッダーを信頼して、元のホスト・プロトコルを判断
--http-enabled HTTPを有効化 TLSをプロキシで終端し、内部はHTTPで受けるとき
--db DBの種類(postgres など) build 時に指定すると起動が速い
--db-url-host / --db-username / --db-password DB接続先 パスワードは環境変数やシークレット管理から渡す
--health-enabled / --metrics-enabled ヘルスチェックとメトリクス 管理用ポート(既定9000)の /health/ready などで公開

本番化の判断表

項目 開発(start-dev) 本番(start)
通信 HTTP可 HTTPS必須(自前TLSかプロキシ終端)
DB 組み込みDB(開発用) PostgreSQLなどの外部DB、バックアップ
ホスト名 自動(localhost) --hostname を固定(iss が変わらないように)
管理ユーザー KC_BOOTSTRAP_ADMIN_* のまま 正式な管理ユーザーを作り、一時ユーザーは削除
管理画面の公開 そのまま 管理画面のパスは社内からのみ到達できるようにする
起動 毎回ビルド build → start --optimized
設定の管理 画面で手作業 kcadm やRealmのエクスポート/インポートでコード化

管理画面での設定チェックリスト

order-web(ブラウザのアプリ)がログインし、order-api(API)を呼ぶ構成を作ります。

# 画面 設定 値の例
1 Manage realms → Create realm Realm名 myrealm
2 Realm roles → Create role ロール order-reader
3 Users → Create new user ユーザー alice、Email verified ON
4 Users → alice → Credentials パスワード Temporary を OFF(ONだと初回に変更を求められる)
5 Users → alice → Role mapping ロールを付与 order-reader
6 Clients → Create client Client ID・種類 order-web、OpenID Connect
7 同上 Capability config 認証方式とフロー Client authentication OFF、Standard flow ON、Direct access grants OFF
8 同上 Login settings URL Valid redirect URIs http://localhost:5173/*、Valid post logout redirect URIs、Web origins http://localhost:5173
9 Clients → order-web → Advanced PKCE Proof Key for Code Exchange Code Challenge Method S256
10 Clients → Create client API用のClient order-api(aud の値として使う。ログイン用のフローはすべてOFF)
11 Clients → order-web → Client scopes → order-web-dedicated → Add mapper Audience Included Client Audience order-api、Add to access token ON
12 Realm settings → Tokens 有効期間 Access Token Lifespan(既定5分)を必要に応じて調整

11のAudienceマッパーを忘れると、アクセストークンの aud にAPI名が入らず、API側の検証で aud 違いになります。 既定では、ロールの設定によって aud が account だけになることがあります。

kcadm(管理CLI)で同じ設定を作る

画面の操作は、kcadm.sh でコマンドにできます(未実行。公式Admin CLIガイドの書式に沿って記載)。

KC=bin/kcadm.sh
$KC config credentials --server http://localhost:8080 --realm master --user admin --password admin

$KC create realms -s realm=myrealm -s enabled=true
$KC create roles -r myrealm -s name=order-reader

$KC create users -r myrealm -s username=alice -s enabled=true -s email=alice@example.com -s emailVerified=true
$KC set-password -r myrealm --username alice --new-password 'ChangeMe-123'
$KC add-roles -r myrealm --uusername alice --rolename order-reader

$KC create clients -r myrealm \
  -s clientId=order-web -s publicClient=true \
  -s standardFlowEnabled=true -s directAccessGrantsEnabled=false \
  -s 'redirectUris=["http://localhost:5173/*"]' \
  -s 'webOrigins=["http://localhost:5173"]' \
  -s 'attributes."pkce.code.challenge.method"=S256'

$KC create clients -r myrealm -s clientId=order-api -s publicClient=false \
  -s standardFlowEnabled=false -s directAccessGrantsEnabled=false

# Audienceマッパー(order-web の id を取得してから追加)
WEB_ID=$($KC get clients -r myrealm -q clientId=order-web --fields id --format csv --noquotes)
$KC create clients/$WEB_ID/protocol-mappers/models -r myrealm \
  -s name=audience-order-api -s protocol=openid-connect \
  -s protocolMapper=oidc-audience-mapper \
  -s 'config."included.client.audience"=order-api' \
  -s 'config."access.token.claim"=true' -s 'config."id.token.claim"=false'

設定をコマンドにしておくと、開発・検証・本番で同じRealmを再現できます。 Realm全体は管理画面の Realm settings → Action → Partial export や、kc.sh export / kc.sh import でも移せます。

アクセストークン(JWT)をAPIで検証する

APIは、受け取ったJWTを「JWKSの公開鍵で署名確認 → iss・aud・exp を確認 → ロールで認可」の順に検証します。Keycloakに毎回問い合わせる必要はなく、公開鍵をキャッシュして手元で検証できます。

確認項目 期待する値
署名 ヘッダーの kid に対応するJWKSの公開鍵で検証成功(改ざんの検出)
alg RS256 に固定(想定外のアルゴリズムを受け付けない)
iss https://{hostname}/realms/myrealm(別Realm・別IdPのトークンを区別)
aud order-api(別アプリ向けのトークンを区別)
exp 現在時刻より後(数十秒の猶予)
ロール realm_access.roles に必要なロール

検証用のトークンとJWKSを作る(Keycloakの代わり)

本物のKeycloakが出すトークンと同じクレーム構造(iss・aud・exp・azp・realm_access など)を、手元のRSA鍵で作りました。JWKSは python -m http.server 7860 で /realms/myrealm/protocol/openid-connect/certs として配信しています。

cryptography で作ったRSA 2048ビット鍵の公開鍵をJWKS(kid・use: sig・alg: RS256)にし、秘密鍵で次のクレームを持つトークンをRS256で署名しています:exp(5分後)・iat・jti・iss(http://localhost:8080/realms/myrealm)・aud(order-api)・sub・typ: Bearer・azp: order-web・scope・realm_access.roles(order-reader など)・resource_access・preferred_username。

この正しいトークン(valid)をもとに、exp を過去にした「期限切れ」、aud を account にした「aud違い」、iss を別Realmにした「iss違い」、ロールを外した「ロールなし」を作りました。さらに、①ペイロードにロール order-admin を書き足して署名はそのままにした「改ざん」、②HS256で作った「アルゴリズム違い」、③別の鍵・未知の kid(rotated-key-2)で署名した「鍵が見つからない」の3つを加え、計8パターンを用意しました。

Python(PyJWT)での検証コード

# verify.py  pip install "pyjwt[crypto]"   (確認:PyJWT 2.15.1 / cryptography 50.0.2 / Python 3.11)
import jwt
from jwt import PyJWKClient

ISSUER = "http://localhost:8080/realms/myrealm"
AUDIENCE = "order-api"
JWKS_URL = "http://127.0.0.1:7860/realms/myrealm/protocol/openid-connect/certs"
# 本物のKeycloakなら f"{ISSUER}/protocol/openid-connect/certs"

jwks_client = PyJWKClient(JWKS_URL, cache_keys=True, lifespan=300)

def verify_access_token(token: str, required_role: str | None = None) -> dict:
    signing_key = jwks_client.get_signing_key_from_jwt(token)   # ヘッダーのkidで公開鍵を選ぶ
    claims = jwt.decode(
        token,
        signing_key.key,
        algorithms=["RS256"],            # 受け付けるアルゴリズムを固定する
        audience=AUDIENCE,
        issuer=ISSUER,
        leeway=30,                       # 時計のずれを30秒まで許容
        options={"require": ["exp", "iat", "iss", "aud", "sub"]},
    )
    if required_role:
        roles = claims.get("realm_access", {}).get("roles", [])
        if required_role not in roles:
            raise PermissionError(f"role '{required_role}' がありません: {roles}")
    return claims

# 確認用:tokens.json の8つのトークンで verify_access_token(t, required_role="order-reader") を呼び、
# 成功なら sub・ユーザー名・ロール、失敗なら例外名とメッセージを表示

実行結果:

valid         OK   sub=3f6c1c1e-0000-4000-8000-000000000001 user=alice roles=['order-reader', 'default-roles-myrealm']
expired       NG   ExpiredSignatureError: Signature has expired
wrong_aud     NG   InvalidAudienceError: Audience doesn't match
wrong_iss     NG   InvalidIssuerError: Invalid issuer
no_role       NG   PermissionError: role 'order-reader' がありません: ['default-roles-myrealm']
tampered      NG   InvalidSignatureError: Signature verification failed
hs256_forged  NG   InvalidAlgorithmError: The specified alg value is not allowed
unknown_kid   NG   PyJWKClientError: Unable to find a signing key that matches: "rotated-key-2"

8パターン中、正しいトークンだけが通り、残り7つはそれぞれ別の例外で止まりました。 例外の種類で原因がわかるので、ログには例外名を残しておくと調査が速くなります。

つまずきやすい書き方(直す前と後)

# 直す前:algorithms を省略
jwt.decode(token, key)
# → DecodeError: It is required that you pass in a value for the "algorithms" argument when calling decode().

# 直す前:トークンに aud があるのに audience を渡していない
jwt.decode(token, key, algorithms=["RS256"])
# → InvalidAudienceError: Invalid audience

# 直した後
jwt.decode(token, key, algorithms=["RS256"], audience="order-api", issuer=ISSUER)

(上の2つのエラー文は、同じトークンで実際に出力されたものです。)

PyJWTは aud を含むトークンに audience 指定がないと検証を通しません。 options={"verify_aud": False} で回避するのではなく、Keycloak側でAudienceマッパーを設定し、APIで audience を指定するのが正しい直し方です。

Node(jose)での検証コード

// verify.mjs  npm install jose   (確認:jose 6.2.12 / Node 22)
import { createRemoteJWKSet, jwtVerify } from 'jose';

const ISSUER = 'http://localhost:8080/realms/myrealm';
const JWKS = createRemoteJWKSet(
  new URL('http://127.0.0.1:7860/realms/myrealm/protocol/openid-connect/certs') // 本物は `${ISSUER}/protocol/openid-connect/certs`
);

export async function verifyAccessToken(token, requiredRole) {
  const { payload } = await jwtVerify(token, JWKS, {
    issuer: ISSUER,
    audience: 'order-api',
    algorithms: ['RS256'],
    clockTolerance: 30,
  });
  const roles = payload.realm_access?.roles ?? [];
  if (requiredRole && !roles.includes(requiredRole)) throw new Error(`role ${requiredRole} がありません`);
  return payload;
}

// 確認用:Pythonと同じ8つのトークンで verifyAccessToken(t, 'order-reader') を呼び、結果を表示

実行結果:

valid         OK alice
expired       NG ERR_JWT_EXPIRED - "exp" claim timestamp check failed
wrong_aud     NG ERR_JWT_CLAIM_VALIDATION_FAILED - unexpected "aud" claim value
wrong_iss     NG ERR_JWT_CLAIM_VALIDATION_FAILED - unexpected "iss" claim value
no_role       NG Error - role order-reader がありません
tampered      NG ERR_JWS_SIGNATURE_VERIFICATION_FAILED - signature verification failed
hs256_forged  NG ERR_JOSE_ALG_NOT_ALLOWED - "alg" (Algorithm) Header Parameter value not allowed
unknown_kid   NG ERR_JWKS_NO_MATCHING_KEY - no applicable key found in the JSON Web Key Set

createRemoteJWKSet は鍵をキャッシュし、未知の kid が来たときだけ取り直します。 Keycloakで鍵をローテーションしても、APIの再起動は不要です。Expressなどでは、Authorization: Bearer ヘッダーから取り出したトークンを verifyAccessToken() に渡すミドルウェアにします。

Spring Security(Resource Server)の設定例

Spring Bootでは spring-boot-starter-oauth2-resource-server を使います(この記事の環境ではMaven Centralに接続できないため未実行)。

# application.yml
spring:
  security:
    oauth2:
      resourceserver:
        jwt:
          issuer-uri: http://localhost:8080/realms/myrealm   # 起動時にDiscoveryからJWKSの場所を取得
          audiences: order-api
// import は org.springframework.security.* と java.util.* (省略)

@Configuration
public class SecurityConfig {

    @Bean
    SecurityFilterChain api(HttpSecurity http) throws Exception {
        http
            .authorizeHttpRequests(auth -> auth
                .requestMatchers("/api/orders/**").hasRole("order-reader")
                .anyRequest().authenticated())
            .oauth2ResourceServer(oauth -> oauth
                .jwt(jwt -> jwt.jwtAuthenticationConverter(keycloakRoles())));
        return http.build();
    }

    // realm_access.roles を ROLE_xxx に変換する(既定では scope クレームしか見ない)
    private JwtAuthenticationConverter keycloakRoles() {
        JwtAuthenticationConverter converter = new JwtAuthenticationConverter();
        converter.setJwtGrantedAuthoritiesConverter(jwt -> {
            Map<String, Object> realm = jwt.getClaim("realm_access");
            if (realm == null) return List.of();
            @SuppressWarnings("unchecked")
            Collection<String> roles = (Collection<String>) realm.getOrDefault("roles", List.of());
            return roles.stream()
                .map(r -> (GrantedAuthority) new SimpleGrantedAuthority("ROLE_" + r))
                .toList();
        });
        return converter;
    }
}

Spring Securityは既定で scope クレームから権限(SCOPE_xxx)を作るため、Keycloakのロールを使うには変換が必要です。

よくあるエラーと対処

症状・メッセージ 原因 対処
ログイン画面に Invalid parameter: redirect_uri Valid redirect URIs と一致しない 末尾の /*、ポート、http/https まで合わせる
API で aud 違い(PyJWT:Audience doesn't match) Audienceマッパー未設定で aud が account など Client Scope に Audience マッパーを追加
API で iss 違い(Invalid issuer) --hostname とAPIの設定が違う/プロキシ経由で別URLになっている iss を固定し、APIの issuer と完全一致させる
Signature has expired が頻発 アクセストークンの有効期間(既定5分)切れ リフレッシュトークンで更新。サーバー間の時刻同期と leeway
鍵が見つからない(Unable to find a signing key) 鍵のローテーション後、または別Realmのトークン JWKSのキャッシュ更新を確認、Realmを確認
ブラウザでトークン取得がCORSエラー Web origins 未設定 アプリのオリジンを Web origins に追加
PKCE関連のエラーでトークン交換できない PKCE必須なのに code_challenge を送っていない、code_verifier 不一致 クライアントライブラリでPKCEを有効化
本番起動でHTTPSの設定を求められて起動しない start はHTTPSが前提 証明書を指定するか、プロキシ終端なら --http-enabled=true と --proxy-headers

よくある質問

Q. アクセストークンの検証はKeycloakに毎回問い合わせる必要がありますか? A. いいえ。JWKSの公開鍵をキャッシュして、API側で署名と iss・aud・exp を検証できます。 即時の無効化(ログアウト直後に使えなくする)が必要な場合は、アクセストークンの有効期間を短くするか、トークンイントロスペクション(Keycloakへの問い合わせ)を併用します。

Q. SPAのクライアントは public と confidential のどちらにしますか? A. ブラウザだけで動くSPAは public(Client authentication OFF)+PKCE にします。ブラウザにシークレットを置いても隠せないためです。サーバー側でトークンを扱う構成(BFF)なら confidential にできます。

Q. Realmロールとクライアントロールはどう使い分けますか? A. 複数のアプリで共通の役割(例:order-reader)は Realmロール、特定のAPIだけの細かい権限は クライアントロール が整理しやすいです。JWTでは前者が realm_access.roles、後者が resource_access.{client}.roles に入ります。

まとめ

  • KeycloakはログインとトークンをまとめるIdP。アプリ用には master ではなく専用のRealmを作る
  • SPAは public client + Standard flow + PKCE(S256)。redirect URIs と Web origins を正確に
  • APIに渡すトークンの aud は Audience マッパーで設定し、API側で audience を指定して検証する
  • JWT検証は JWKS の公開鍵で署名、alg 固定、iss・aud・exp・ロールの確認。8パターン中、正しいトークンだけが通ることを確認した
  • 本番は build → start --optimized、外部DB・HTTPS・固定hostname。プロキシ終端なら --proxy-headers
  • 設定は kcadm やエクスポートでコード化して、環境ごとに同じRealmを再現する

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「Keycloak入門|OIDCログインとJWT検証を最短で構築」

株式会社RJCでは、Keycloakを使った認証基盤の仕組みを仲間と学び合っています。こうした知識を共有しながら、日々技術を磨いています。

株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。

WE ARE HIRING

RJCで一緒に開発しながら、
成長を楽しみませんか?

RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!

  • 127日年間休日
  • 12時間平均残業時間
  • 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!

ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。

ABOUT RJC RJCがどんな会社か知る 考え方、研修、働き方、福利厚生、社員の前職まで。RJCのことが丸わかり! RJC丸わかりページへ JOB DESCRIPTION 仕事内容・待遇を見てみる 仕事内容、給与・待遇、選考の流れ。経験者も未経験も!応募前に知りたいこと、まとめました! 募集要項を見る ENTRY エントリーする エントリーは1〜2分・履歴書不要です。まずは話を聞いてみたい、という方でも歓迎です! エントリーフォームへ

RJCで一緒に開発しながら、 成長を楽しみませんか?