Skip to content
IRC-Coding IRC-Coding
OAuth 2.0 Authorization Code Flow Access Token Refresh Token API Security

OAuth 2.0: Authorization Code Flow & Access Token

OAuth 2.0 authorization framework guide. Learn authorization code flow, client credentials, access and refresh tokens with code examples.

S

schutzgeist

2 min read
OAuth 2.0: Authorization Code Flow & Access Token

OAuth 2.0: Authorization Code, Flows & Access Token

This article is a glossary entry on the OAuth 2.0 authorization framework – including flows, tokens and practical implementation.

In a Nutshell

OAuth 2.0 is a standardized authorization framework that allows third parties to access user resources without knowing their credentials.

Compact Technical Description

OAuth 2.0 is a widespread authorization protocol for web, desktop and mobile applications. It enables an application (client) to access resources of another system (resource server) on behalf of a user.

Core characteristics:

  • Delegation: Users delegate access rights to applications
  • Token-based: Access tokens instead of passwords
  • Role-based: Clear separation of involved actors
  • Standardized: RFC 6749 defines the framework

Involved roles:

  • Resource Owner: User who owns the resources
  • Client: Application that wants to access resources
  • Authorization Server: Issues tokens and validates them
  • Resource Server: Provides the protected resources

OAuth 2.0 does not transmit user identity, but merely authorizes access to resources. For identity verification, there is OpenID Connect.

Exam-Relevant Key Points

  • Authorization framework, not authentication
  • Roles: Resource Owner, Client, Authorization Server, Resource Server
  • Access Token and optionally Refresh Token
  • Authorization Code Flow for web applications
  • Client Credentials Flow for server-to-server communication
  • HTTP-based and supports REST APIs (relevant for IHK)
  • Token-based access increases security
  • Protection against password sharing through delegation mechanism

Core Components

  1. Resource Owner: User or system that owns the resources
  2. Client: Application that needs access to resources
  3. Authorization Server: Issues tokens and verifies them
  4. Resource Server: Hosts the protected resources
  5. Access Token: Short-lived token for resource access
  6. Refresh Token: Long-lived token for token renewal
  7. Authorization Code: Temporary code for token exchange
  8. Redirect URI: Target URL after authorization
  9. Scope: Defines the access scope
  10. Grant Type: Determines the OAuth 2.0 flow

OAuth 2.0 Flows

1. Authorization Code Flow (for Web Apps)

1. Client → User: Redirect to Authorization Server
2. User → Authorization Server: Login & consent
3. Authorization Server → Client: Authorization Code
4. Client → Authorization Server: Exchange code for Access Token
5. Authorization Server → Client: Access Token + Refresh Token
6. Client → Resource Server: Request resources with Access Token

2. Client Credentials Flow (for Server-to-Server)

1. Client → Authorization Server: Send Client Credentials
2. Authorization Server → Client: Access Token
3. Client → Resource Server: Request resources with Access Token

3. Implicit Flow (deprecated, for Single-Page Apps)

1. Client → User: Redirect to Authorization Server
2. User → Authorization Server: Login & consent
3. Authorization Server → Client: Access Token directly in fragment

Practical Examples

Authorization Code Flow Implementation

// Frontend: Request authorization
const authUrl = 'https://auth.example.com/authorize';
const params = new URLSearchParams({
  response_type: 'code',
  client_id: 'your_client_id',
  redirect_uri: 'https://yourapp.com/callback',
  scope: 'read:profile write:data',
  state: generateRandomString() // CSRF protection
});

window.location.href = `${authUrl}?${params}`;

// Callback handler
async function handleCallback(code, state) {
  // Validate state
  if (state !== getStoredState()) {
    throw new Error('Invalid state - CSRF attack detected');
  }
  
  // Exchange code for token
  const tokenResponse = await fetch('https://auth.example.com/token', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/x-www-form-urlencoded',
    },
    body: new URLSearchParams({
      grant_type: 'authorization_code',
      code: code,
      client_id: 'your_client_id',
      client_secret: 'your_client_secret',
      redirect_uri: 'https://yourapp.com/callback'
    })
  });
  
  const tokens = await tokenResponse.json();
  localStorage.setItem('access_token', tokens.access_token);
  localStorage.setItem('refresh_token', tokens.refresh_token);
}

Backend: Token Validation

// Spring Boot Example
@RestController
@RequestMapping("/api")
public class ApiController {
    
    @GetMapping("/profile")
    public ResponseEntity<UserProfile> getProfile(
            @RequestHeader("Authorization") String authHeader) {
        
        // Extract and validate token
        String token = authHeader.replace("Bearer ", "");
        
        if (!tokenValidator.isValid(token)) {
            return ResponseEntity.status(401).build();
        }
        
        // Extract token claims
        Claims claims = tokenValidator.getClaims(token);
        String userId = claims.getSubject();
        List<String> scopes = claims.get("scope", List.class);
        
        // Scope check
        if (!scopes.contains("read:profile")) {
            return ResponseEntity.status(403).build();
        }
        
        UserProfile profile = userService.getProfile(userId);
        return ResponseEntity.ok(profile);
    }
    
    @PostMapping("/data")
    public ResponseEntity<?> createData(
            @RequestHeader("Authorization") String authHeader,
            @RequestBody DataRequest request) {
        
        String token = authHeader.replace("Bearer ", "");
        
        if (!tokenValidator.isValid(token)) {
            return ResponseEntity.status(401).build();
        }
        
        Claims claims = tokenValidator.getClaims(token);
        List<String> scopes = claims.get("scope", List.class);
        
        // Check write permission
        if (!scopes.contains("write:data")) {
            return ResponseEntity.status(403).build();
        }
        
        Data data = dataService.create(request, claims.getSubject());
        return ResponseEntity.ok(data);
    }
}

Client Credentials Flow

# Python example for server-to-server communication
import requests

def get_access_token():
    token_url = "https://auth.example.com/token"
    
    data = {
        'grant_type': 'client_credentials',
        'client_id': 'your_client_id',
        'client_secret': 'your_client_secret',
        'scope': 'api:read api:write'
    }
    
    response = requests.post(token_url, data=data)
    response.raise_for_status()
    
    token_data = response.json()
    return token_data['access_token']

def api_call():
    access_token = get_access_token()
    
    headers = {
        'Authorization': f'Bearer {access_token}',
        'Content-Type': 'application/json'
    }
    
    response = requests.get(
        'https://api.example.com/data',
        headers=headers
    )
    
    return response.json()

Refresh Token Flow

// Token renewal with Refresh Token
async function refreshAccessToken() {
  const refreshToken = localStorage.getItem('refresh_token');
  
  if (!refreshToken) {
    throw new Error('No refresh token available');
  }
  
  try {
    const response = await fetch('https://auth.example.com/token', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/x-www-form-urlencoded',
      },
      body: new URLSearchParams({
        grant_type: 'refresh_token',
        refresh_token: refreshToken,
        client_id: 'your_client_id',
        client_secret: 'your_client_secret'
      })
    });
    
    if (!response.ok) {
      throw new Error('Token refresh failed');
    }
    
    const tokens = await response.json();
    localStorage.setItem('access_token', tokens.access_token);
    
    if (tokens.refresh_token) {
      localStorage.setItem('refresh_token', tokens.refresh_token);
    }
    
    return tokens.access_token;
  } catch (error) {
    // Refresh token invalid - re-login required
    localStorage.removeItem('access_token');
    localStorage.removeItem('refresh_token');
    redirectToLogin();
  }
}

Security Notes

State Parameter (CSRF Protection)

function generateState() {
  return Math.random().toString(36).substring(2, 15) +
         Math.random().toString(36).substring(2, 15);
}

function storeState(state) {
  sessionStorage.setItem('oauth_state', state);
}

function validateState(receivedState) {
  const storedState = sessionStorage.getItem('oauth_state');
  sessionStorage.removeItem('oauth_state');
  return storedState === receivedState;
}

PKCE (Proof Key for Code Exchange)

// PKCE for mobile/single-page apps
function generatePKCE() {
  const codeVerifier = generateRandomString(128);
  const codeChallenge = base64urlEncode(sha256(codeVerifier));
  
  return { codeVerifier, codeChallenge };
}

// Authorization request with PKCE
const params = new URLSearchParams({
  response_type: 'code',
  client_id: 'your_client_id',
  code_challenge: pkce.codeChallenge,
  code_challenge_method: 'S256',
  redirect_uri: 'https://yourapp.com/callback'
});

Advantages and Disadvantages

Advantages

  • Security: No password sharing with third parties
  • Standardization: Widely adopted and well documented
  • Flexibility: Different flows for different use cases
  • Scalability: Central authorization for many services
  • Revocation: Tokens can be revoked at any time

Disadvantages

  • Complexity: More steps than simple authentication
  • Performance: Additional network calls for token renewal
  • State Management: Client must manage token state
  • Security Risks: Incorrect implementation can create security gaps

Frequently Asked Exam Questions

  1. What is the difference between OAuth 2.0 and OpenID Connect? OAuth 2.0 is for authorization, OpenID Connect adds identity (authentication).

  2. Explain the Authorization Code Flow! Client redirects user to Authorization Server, receives code, exchanges code for token.

  3. When do you use Client Credentials Flow? For server-to-server communication without user interaction.

  4. What is the purpose of the State Parameter? CSRF protection by verifying that the request was initiated by the client.

Most Important Sources

  1. https://tools.ietf.org/html/rfc6749
  2. https://oauth.net/2/
  3. https://auth0.com/docs/authorization-framework/overview
Back to Blog
Share:

Related Posts