---
title: App Access Token Oluşturma
description: ikas AppBridge ve signature doğrulama ile JWT token alma
---

Uygulamanızı bir mağazaya başarıyla yetkilendirdikten sonra, uygulamanızın API'lerine erişirken kullanılacak bir access token oluşturmamız gerekiyor. Bunu yapmanın en kolay yolu ikas AppBridge kullanmaktır.

ikas AppBridge ile ikas Dashboard'dan App Secret'ınız ile şifrelenmiş bir JWT Token talep edebilirsiniz, böylece server tarafında doğrulayabilirsiniz.

İkinci yöntem ise internal API aracılığıyla query param signature'ını doğrulamaktır. Mağaza sahibi uygulamanızı ikas Dashboard'da açtığında, ikas uygulamanızın URL'ine belirli query parametreleri ekleyerek yönlendirir. Bu parametreleri app secret'ınızı kullanarak doğrulayabilirsiniz.

## ikas AppBridge ile Token Oluşturma

### Token Helpers Oluşturma

İlk olarak ikas AppBridge kullanarak token yaşam döngüsünü yöneten bir helper sınıf oluşturacağız.

`lib/token-helpers.ts` dosyasını oluşturun:

```typescript title="File: lib/token-helpers.ts"
import { useRouter } from 'next/navigation';

const TOKEN_KEY = 'token';

export class TokenHelpers {
  /**
   * Bu metodu yalnızca uygulamanız ikas dashboard içinde IFrame'de görüntüleniyorsa kullanabilirsiniz
   */
  static getTokenForIframeApp = async (router: ReturnType<typeof useRouter>) => {
    let token = sessionStorage.getItem(TOKEN_KEY);
    
    if (token) {
      const tokenData = JSON.parse(atob(token.split('.')[1]));
      // Token süresi dolmamışsa döndür
      if (new Date().getTime() < tokenData.exp * 1000) return { success: true, token };
    }
    
    // Token'ın IFrame içinde olup olmadığını kontrol et
    if (typeof window !== 'undefined' && window.self !== window.top) {
      try {
        // Session storage'da bulunamazsa AppBridge'den token al
        const appBridgeToken = await getNewTokenFromAppBridge();
        if (appBridgeToken) {
          sessionStorage.setItem(TOKEN_KEY, appBridgeToken);
          return { success: true, token: appBridgeToken };
        }
      } catch (error) {
        console.error('AppBridge token request failed:', error);
      }
      
      router.push('/authorize-store');
      return { success: false, error: 'Token alınamadı' };
    }
    
    return { success: false, error: 'IFrame dışında çalışıyor' };
  };
}

/**
 * AppBridge üzerinden token alma fonksiyonu
 */
function getNewTokenFromAppBridge(): Promise<string | null> {
  return new Promise((resolve, reject) => {
    const timeoutId = setTimeout(() => {
      window.removeEventListener('message', messageHandler);
      reject(new Error('AppBridge token timeout'));
    }, 5000);

    const messageHandler = (event: MessageEvent) => {
      if (event.data?.type === 'TOKEN_RESPONSE') {
        clearTimeout(timeoutId);
        window.removeEventListener('message', messageHandler);
        resolve(event.data.token || null);
      }
    };

    window.addEventListener('message', messageHandler);
    
    if (window.parent && window.parent !== window) {
      window.parent.postMessage({ type: 'REQUEST_TOKEN' }, '*');
    } else {
      reject(new Error('Not running in iframe context'));
    }
  });
}
```

### Ana Sayfa Güncelleme

Token almak ve Dashboard sayfasına yönlendirmek için load fonksiyonunu güncelleyin:

```typescript title="File: app/page.tsx"
'use client';

import { useEffect } from 'react';
import { useRouter } from 'next/navigation';
import { TokenHelpers } from '@/lib/token-helpers';

export default function Home() {
  const router = useRouter();

  useEffect(() => {
    const load = async () => {
      // Loader'ı kapat
      if (typeof window !== 'undefined' && window.parent) {
        window.parent.postMessage({ type: 'CLOSE_LOADER' }, '*');
      }
      
      // Session storage'dan veya ikas AppBridge üzerinden token al
      const tokenResult = await TokenHelpers.getTokenForIframeApp(router);
      if (tokenResult.success) {
        await router.push('/dashboard');
      } else {
        router.push('/authorize-store');
      }
    };

    load();
  }, [router]);

  return (
    <main className="min-h-screen flex items-center justify-center">
      <div className="text-center">
        <div className="animate-spin rounded-full h-8 w-8 border-b-2 border-blue-600 mx-auto mb-4"></div>
        <p className="text-gray-600">Yükleniyor...</p>
      </div>
    </main>
  );
}
```

<Callout type="success" title="AppBridge Token">
ikas Dashboard'a gidip "Uygulamalarım" sayfasından uygulamanızı bulup tıklayın. Uygulamanız yüklendikten sonra başarı mesajı görürseniz, uygulamanız ikas AppBridge'den başarıyla yeni bir token almış demektir.
</Callout>

## Signature Kontrolü ile Token Oluşturma

External uygulamaların ikas AppBridge'e erişimi olmadığı için ikas tarafından uygulamanızın URL'ine eklenen query parametrelerini doğrulamanız gerekir.

Mağaza sahibi uygulamanızı tıkladığında, ikas uygulamanızın URL'ine `authorizedAppId`, `merchantId`, `signature`, `storeName`, `timestamp` parametrelerini ekleyerek yönlendirir.

`signature`'ı doğrulamak için App Secret'ınızla `${storeName}${merchantId}${timestamp}` değerinin SHA256 hash'ini hesaplamalı ve `signature` ile karşılaştırmalısınız.

### Signature Doğrulama API'si

`app/api/get-token-with-signature/route.ts` dosyasını oluşturun:

```typescript title="File: app/api/get-token-with-signature/route.ts"
import { NextRequest, NextResponse } from 'next/server';
import { validateAuthSignature } from '@ikas/api-client';
import { config } from '@/globals/config';
import { JwtHelpers } from '@/lib/jwt-helpers';

export interface GetTokenWithSignatureRequest {
  authorizedAppId: string;
  merchantId: string;
  signature: string;
  storeName: string;
  timestamp: string;
}

export interface GetTokenWithSignatureResponse {
  token: string;
}

export async function POST(request: NextRequest) {
  try {
    const data = await request.json() as GetTokenWithSignatureRequest;
    
    // Gerekli alanları kontrol et
    if (!data.authorizedAppId || !data.merchantId || !data.signature || !data.storeName || !data.timestamp) {
      return NextResponse.json(
        { error: 'Gerekli alanlar eksik' },
        { status: 400 }
      );
    }
    
    // Signature'ı doğrula
    const isSignatureValid = validateAuthSignature(data, config.appSecret);
    
    if (isSignatureValid) {
      const token = JwtHelpers.createToken(data.merchantId, data.authorizedAppId);
      return NextResponse.json({ token });
    } else {
      return NextResponse.json(
        { error: 'Signature doğrulaması başarısız' },
        { status: 401 }
      );
    }
  } catch (error) {
    return NextResponse.json(
      { error: 'Token oluşturma hatası' },
      { status: 500 }
    );
  }
}
```

### API Requests Helper

`lib/api-requests.ts` dosyasını oluşturun:

```typescript title="File: lib/api-requests.ts"
import axios from 'axios';
import { GetTokenWithSignatureRequest, GetTokenWithSignatureResponse } from '@/app/api/get-token-with-signature/route';

export const ApiRequests = {
  getTokenWithSignature: (data: GetTokenWithSignatureRequest) => 
    axios.post<GetTokenWithSignatureResponse>('/api/get-token-with-signature', data),
};
```

### Token Helpers Güncelleme

`lib/token-helpers.ts` dosyasına external app desteği ekleyin:

```typescript title="File: lib/token-helpers.ts (güncelleme)"
import { ApiRequests } from './api-requests';

export class TokenHelpers {
  // ... önceki getTokenForIframeApp metodu

  /**
   * External uygulamalar için token alma
   */
  static getTokenForExternalApp = async (router: any, params: URLSearchParams) => {
    if (params.has('storeName')) {
      if (
        params.has('merchantId') &&
        params.has('signature') &&
        params.has('authorizedAppId') &&
        params.has('timestamp')
      ) {
        const connectParams = {
          authorizedAppId: params.get('authorizedAppId')!,
          merchantId: params.get('merchantId')!,
          signature: params.get('signature')!,
          storeName: params.get('storeName')!,
          timestamp: params.get('timestamp')!,
        };
        
        try {
          const res = await ApiRequests.getTokenWithSignature(connectParams);
          if (res.status === 200 && res.data?.token) {
            sessionStorage.setItem(TOKEN_KEY, res.data.token);
            return res.data.token;
          }
        } catch (error) {
          console.error('Token signature validation failed:', error);
        }
      }
      
      window.location.replace(`/api/oauth/authorize?storeName=${params.get('storeName')}`);
      return;
    }
    
    await router.push('/authorize-store');
  };
}
```

### Ana Sayfa Final Güncelleme

Her iki token alma yöntemini de destekleyecek şekilde ana sayfayı güncelleyin:

```typescript title="File: app/page.tsx (final)"
'use client';

import { useEffect } from 'react';
import { useRouter } from 'next/navigation';
import { TokenHelpers } from '@/lib/token-helpers';

export default function Home() {
  const router = useRouter();

  useEffect(() => {
    const load = async () => {
      // Loader'ı kapat
      if (typeof window !== 'undefined' && window.parent) {
        window.parent.postMessage({ type: 'CLOSE_LOADER' }, '*');
      }
      
      const params = new URLSearchParams(window.location.search);
      
      // İlk olarak AppBridge'den token almaya çalış
      let tokenResult = await TokenHelpers.getTokenForIframeApp(router);
      
      if (!tokenResult.success) {
        // AppBridge başarısız olursa external app yöntemini dene
        const externalToken = await TokenHelpers.getTokenForExternalApp(router, params);
        if (externalToken) {
          await router.push('/dashboard');
          return;
        }
      } else {
        await router.push('/dashboard');
      }
    };

    load();
  }, [router]);

  return (
    <main className="min-h-screen flex items-center justify-center">
      <div className="text-center">
        <div className="animate-spin rounded-full h-8 w-8 border-b-2 border-blue-600 mx-auto mb-4"></div>
        <p className="text-gray-600">Yükleniyor...</p>
      </div>
    </main>
  );
}
```

## JWT Helpers

`lib/jwt-helpers.ts` dosyasını oluşturun:

```typescript title="File: lib/jwt-helpers.ts"
import jwt from 'jsonwebtoken';
import { config } from '@/globals/config';

export interface JwtPayload {
  sub: string; // merchantId
  aud: string; // authorizedAppId
  exp: number;
  iat: number;
}

export class JwtHelpers {
  static createToken(merchantId: string, authorizedAppId: string): string {
    if (!config.appSecret) {
      throw new Error('JWT secret not configured');
    }

    return jwt.sign(
      {
        sub: merchantId,
        aud: authorizedAppId,
      },
      config.appSecret,
      {
        expiresIn: '1h',
        algorithm: 'HS256',
      }
    );
  }

  static verifyToken(token: string): JwtPayload | null {
    if (!config.appSecret) {
      return null;
    }

    try {
      return jwt.verify(token, config.appSecret) as JwtPayload;
    } catch (error) {
      return null;
    }
  }
}
```

<Callout type="success" title="Token Sistemi Hazır">
Bu noktada hem internal (iframe) hem de external uygulamalar için token oluşturma ve doğrulama sistemi hazır! Artık mağaza sahibinin uygulamanızı ikas Dashboard'dan güvenli şekilde kullanabileceği bir authentication sisteminiz var.
</Callout>

<Callout type="info" title="Sonraki Adım">
Token sisteminizi kurduktan sonra, bu token'ları kullanarak ikas GraphQL API'sine nasıl erişeceğinizi öğrenmek için [ikas SDK Kullanımı](/docs/app-development/ikas-sdk-kullanimi) rehberine geçin.
</Callout>